CircleCI环境下Python调用谷歌服务账号认证时遇OSError: [Errno 36]文件名过长的解决办法
问题根源
你遇到的核心问题是对google.oauth2.service_account.Credentials.from_service_account_file()方法的使用误解:这个方法的参数要求是服务账号JSON文件的路径,但你现在直接传入了解码后的完整JSON字符串。Python会把这个超长的字符串当作文件名去尝试打开,自然就触发了「文件名过长」的OSError。
最优解决方案:使用from_service_account_info替代
谷歌的认证库提供了专门接收JSON字典的方法from_service_account_info(),不需要生成临时文件,直接处理环境变量中的JSON字符串即可,步骤如下:
先修正CircleCI中环境变量的导出命令
你原来的导出命令会给环境变量值额外添加一层双引号,导致后续JSON解析失败。修改为不带多余引号的版本:# 修正后的导出命令(去掉包裹的双引号) echo 'export SERVICE_ACCOUNT_DECODED=$(echo "$SERVICE_ACCOUNT" | base64 -di)' >> "$BASH_ENV"或者用更安全的
printf避免转义问题:printf 'export SERVICE_ACCOUNT_DECODED=%s\n' "$(echo "$SERVICE_ACCOUNT" | base64 -di)" >> "$BASH_ENV"Python代码调整
直接解析环境变量中的JSON字符串为字典,传给from_service_account_info():import os import json from google.oauth2 import service_account # 替换为你的实际权限范围 SCOPES = ['https://www.googleapis.com/auth/drive'] try: # 从环境变量获取解码后的JSON字符串,解析为字典 service_account_info = json.loads(os.environ['SERVICE_ACCOUNT_DECODED']) # 使用from_service_account_info直接传入字典 credentials = service_account.Credentials.from_service_account_info( service_account_info, scopes=SCOPES ) except json.JSONDecodeError as e: print(f"解析服务账号JSON失败: {e}") # 这里可以添加自定义错误处理逻辑
为什么之前json.loads()没生效?
大概率是因为你原来的环境变量导出命令中,给SERVICE_ACCOUNT_DECODED的值加了额外的双引号(比如"{\n...}"这种格式),导致json.loads()无法正确解析带外层引号的字符串。修正导出命令去掉多余引号后,json.loads()就能正常工作了。
备选方案:使用临时文件(不推荐)
如果你一定要用from_service_account_file()方法,可以把JSON字符串写入临时文件后再传入路径:
import os import json import tempfile from google.oauth2 import service_account SCOPES = ['https://www.googleapis.com/auth/drive'] sa_json_str = os.environ['SERVICE_ACCOUNT_DECODED'] # 创建临时JSON文件 with tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.json', encoding='utf-8') as temp_file: temp_file.write(sa_json_str) temp_file_path = temp_file.name try: credentials = service_account.Credentials.from_service_account_file( temp_file_path, scopes=SCOPES ) finally: # 用完后删除临时文件,避免残留 os.unlink(temp_file_path)
这个方案需要处理文件创建和清理,不如直接用from_service_account_info简洁高效。
备注:内容来源于stack exchange,提问作者Milenko Markovic

