You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

CircleCI环境下Python调用谷歌服务账号认证时遇OSError: [Errno 36]文件名过长的解决办法

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字符串即可,步骤如下:

  1. 先修正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"
    
  2. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 12:29:52