本文针对 OpenClaw 接入 Google Gemini 时 OAuth 完成后仍报 loadCodeAssist 400 Bad Request 的典型故障,系统梳理了鉴权回调、请求参数、环境变量与代理链路的排查顺序,并给出可复现、可回滚的修复步骤。文末附带常见误配置清单与上线前自检要点,帮助你在团队环境中稳定落地。
# OpenClaw Gemini OAuth 登录失败修复指南:loadCodeAssist 400 Bad Request
## 问题现象
在使用 OpenClaw 配置 Google Gemini CLI 时,执行登录命令后浏览器端 OAuth 授权成功,但 CLI 端仍然报错:
openclaw models auth login --provider google-gemini-cli --set-default
Gemini CLI OAuth failed
Error: loadCodeAssist failed: 400 Bad Request
常见于已开通 Google One Pro 或 Cloud Code Assist 付费层的账号,免费层反而较少遇到。
## 根因分析
问题**不在** Google 账号权限,也**不在**本地 OAuth 回调端口。
真正的失败点在 OAuth 成功之后:
浏览器登录 → OAuth token 获取成功 ✅
↓
调用 cloudcode-pa.googleapis.com/v1internal:loadCodeAssist
↓
推断 projectId → 偶发返回 400 Bad Request ❌
↓
OpenClaw 将 400 视为致命错误 → 整个登录流程回滚
关键发现:
– 同一份 token 再次请求 `loadCodeAssist`,很多时候其实能成功
– 账号真实可用,能正常调用 `streamGenerateContent`
– 付费账号更依赖 `projectId`,而 `loadCodeAssist` 是获取它的唯一途径
– OpenClaw 早期版本同步凭据时存在丢失 `projectId` 的问题
## 快速诊断清单
遇到此错误时,按顺序检查:
### 1. OAuth 凭据是否已生成
ls -la ~/.gemini/
如果目录下存在 `oauth_access_token`、`oauth_refresh_token` 等文件,说明 OAuth 本身成功了,问题在后续步骤。
### 2. 是否有缓存的 projectId
cat ~/.openclaw/agents/main/agent/auth-profiles.json | grep projectId
如果已有 `projectId`,说明之前登录成功过,可以尝试直接使用。
### 3. 确认执行的是哪个 OpenClaw
which openclaw
如果有多个安装(全局 + 状态目录扩展),需要确认修复的是哪个。
### 4. 区分登录失败 vs 模型限流
登录成功后如果报 `429 RATE_LIMIT_EXCEEDED`,那不是登录问题,是 Google 侧限流。换一个模型(如 `gemini-2.5-pro`)即可。
## 修复方案
### 方案一:设置环境变量(最简单)
如果之前登录成功过,直接设置环境变量绕过项目发现:
# 将已有的 projectId 写入环境变量
export GOOGLE_CLOUD_PROJECT=<your-project-id>
# 永久生效
echo 'export GOOGLE_CLOUD_PROJECT=<your-project-id>' >> ~/.zshrc
然后重新执行登录命令。
### 方案二:重试登录(偶发性问题)
`loadCodeAssist` 返回 400 有随机性,多试几次可能就成功了:
for i in {1..5}; do
echo "Attempt $i..."
openclaw models auth login --provider google-gemini-cli --set-default && break
sleep 2
done
### 方案三:修补 OpenClaw 源码增加重试(根治)
找到 OpenClaw 全局安装目录中的 OAuth 项目发现文件:
find $(dirname $(which openclaw))/../lib/node_modules/openclaw/dist \
-name "oauth.project-*.js" -type f
在该文件中找到 `loadCodeAssist` 调用处,做以下修改:
**1. 增加重试逻辑**
async function loadCodeAssistWithRetry(token, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await loadCodeAssist(token);
} catch (e) {
if (e.status === 400 || e.status === 429 || e.status >= 500) {
if (i < maxRetries - 1) {
await new Promise(r => setTimeout(r, 1000 * (i + 1)));
continue;
}
}
throw e;
}
}
}
**2. 回退读取已缓存的 projectId**
// 如果 loadCodeAssist 失败,尝试从 auth-profiles.json 读取
function getCachedProjectId() {
try {
const profiles = JSON.parse(
fs.readFileSync(path.join(homedir(), '.openclaw/agents/main/agent/auth-profiles.json'))
);
for (const profile of Object.values(profiles.profiles || {})) {
if (profile.projectId) return profile.projectId;
}
} catch {}
return null;
}
**3. 允许付费账号直接复用已知项目**
const projectId = await loadCodeAssistWithRetry(token)
.catch(() => getCachedProjectId());
if (!projectId) throw new Error('Cannot determine projectId');
### 方案四:使用 API Key 模式(绕过 OAuth)
如果 OAuth 反复失败,可以直接用 Gemini API Key:
# 在 openclaw.json 中配置 gemini-api provider
{
"models": {
"providers": {
"gemini-api": {
"baseUrl": "https://generativelanguage.googleapis.com/v1beta",
"apiKey": "<your-gemini-api-key>",
"api": "google-generative-ai",
"models": [
{
"id": "gemini-2.5-pro",
"name": "Gemini 2.5 Pro",
"api": "google-generative-ai",
"reasoning": true,
"input": ["text", "image"],
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 },
"contextWindow": 1000000,
"maxTokens": 65536
}
]
}
}
}
}
API Key 从 [Google AI Studio](https://aistudio.google.com/apikey) 获取,免费额度足够日常使用。
## 推荐模型选择
| 模型 | 稳定性 | 适用场景 |
|——|——–|———-|
| `gemini-2.5-pro` | ✅ 稳定 | 通用首选 |
| `gemini-3-flash-preview` | ✅ 稳定 | 快速响应 |
| `gemini-3.1-pro-preview` | ⚠️ 常限流 | 不推荐日常使用 |
## 总结
| 要点 | 说明 |
|——|——|
| 问题本质 | `loadCodeAssist` 偶发 400,OpenClaw 未做容错 |
| 最快修复 | 设置 `GOOGLE_CLOUD_PROJECT` 环境变量 |
| 根治方案 | 修改源码增加重试 + projectId 缓存回退 |
| 备选方案 | 使用 API Key 模式绕过 OAuth |
| 注意区分 | 登录失败(400) ≠ 模型限流(429) |
Full-Stack Developer with 10+ years of experience, specializing in QT C++ desktop application development and AI Agent systems.




