Gemini CLI 报 Cannot read properties of undefined (reading 'candidates') 怎么办

2026-08-08

用着用着,蹦出一条一看就不像业务报错的东西:

API Error: Cannot read properties of undefined (reading 'candidates')

或者带方框的那种形式:

✕ [API Error: Cannot read properties of undefined (reading 'candidates')]

对应的是 GitHub 上的 issue #18621 和 #18622(都已关闭)。

这篇先讲清楚这条报错的性质——因为它的性质决定了哪些排查方向是白费力气。绝大多数人在这条上浪费时间,是因为把它当成了配置问题。

一、这是一条 JavaScript 运行时错误,不是 API 业务错误

Cannot read properties of undefined (reading 'xxx') 是 JavaScript 里最常见的一类错误,意思是:代码想从一个东西里取 xxx 这个属性,但那个东西是 undefined

具体到这里:candidates 是 Gemini API 响应体里承载模型输出的那个字段。客户端拿到响应之后,去读 响应.candidates,结果发现要读的那层是空的。

所以真实发生的事情是:服务端返回了一个客户端没预料到的形状,客户端在解析时崩了。

这有几个直接推论,能帮你省掉大半排查:

  • 不是你的配置写错了。 配置错会报配置类错误(Gemini CLI 有专门的 FatalConfigError,退出码 52)
  • 不是认证问题。 认证问题有自己的报错和退出码(41)
  • 不是模型”回答得不好”。 这个阶段还没到内容层面,是解析就挂了
  • 不是你的 prompt 写得有问题。 同样的 prompt 重试可能就过了

换句话说:报错文本里出现 Cannot read properties of undefined 这种措辞时,问题几乎一定在程序内部,而不是在你的输入上。

二、证据状态:没有官方定论

必须说清楚:

  • issue #18621(已关闭,43 条评论)和 #18622(已关闭)都没有给出公认的根因和解法
  • Gemini CLI 仓库自带的 troubleshooting 文档没有收录这条——那份文档覆盖的是认证、安装、沙箱、CI 环境、退出码,没有这一类

所以本文不给「解法」。下面给的是判断方法减损做法

三、能做的排查

第一,重试。

这条报错的性质决定了它很可能是偶发的——服务端某次返回了异常形状。重试一次,多半就过了。

如果重试稳定复现,那才值得往下查,因为这说明有某个确定的触发条件。

第二,看是不是跟某个特定输入绑定。

稳定复现的话,试着改变输入:

  • 换一个文件
  • 把那个请求拆小
  • 换一种说法

如果换了输入就好了,那就锁定了触发条件——虽然你修不了客户端的解析逻辑,但你可以绕开那个输入

第三,升级版本。

这类解析崩溃属于典型的「客户端没处理好边界情况」,通常会在后续版本里加上判空处理。所以:

npm install -g @google/gemini-cli@latest

(如果你是从源码跑的,就 pull 最新代码再 npm run build。)

这条是本文性价比最高的一条建议。 issue 已经关闭意味着相关代码大概率动过——用旧版本撞一个可能已经被修掉的问题,最不划算。

第四,用 --debug 看细节。

官方给的调试手段是 --debug 标志,交互模式下可以按 F12 打开调试控制台。这类崩溃开着 debug 能看到更完整的堆栈和响应内容,判断是哪一层出的问题。

四、什么方向是白费力气

省时间的关键往往是知道别查什么

  • 别去改 settings.json——配置错会报 FatalConfigError(退出码 52),不是这条
  • 别去重新登录——认证问题会报认证类错误(退出码 41)
  • 别去查网络和代理——那类问题的表现是连不上、超时、证书错误,不是解析崩溃
  • 别去调 prompt 措辞——这个阶段还没到内容层面
  • 别去清缓存重装——除非你要顺便升级版本,否则重装同一个版本不改变任何东西

上面这五条是搜这类报错时最容易搜到的「万能建议」,但它们对这条报错都不对症

五、跟它容易混的几条

Gemini CLI 里几条报错都以 API Error: 开头,但性质完全不同:

报错性质该往哪查
Cannot read properties of undefined (reading 'candidates')客户端解析崩溃重试、升级版本;别查配置和网络
got status: 429 Too Many Requests额度或频率上限查你在哪一档(免费 API key 只有 250/天、10/分钟)
503 - The model is overloaded服务端过载等、换模型
Model stream ended with empty response text流结束但内容为空重试;无公认解法
Premature close连接提前关闭重试;无公认解法
0 occurrences found for old_string文本匹配失败(工具层,不是 API)检查空白/缩进/换行差异;重试无用

这张表里,只有 429 有明确且可自查的成因。按官方额度页,Google 登录是 1000 次/天、60 次/分钟;未付费的 API Key 是 250 次/天、10 次/分钟。撞 429 时先确认自己在哪一档。

最后一条 0 occurrences found 值得记住,因为它跟本文这条形成对照:一个是随机的(重试可能好),一个是确定的(重试一定不好)。分清「重试有意义」和「重试没意义」,能省掉大量无效操作。

六、减损

跟其他不可控的偶发故障一样,重点是控制损失:

任务切小。 断在第三步比断在第三十步好收拾。

断了先看当前状态。 它崩之前可能已经改过文件。直接重发同一个请求可能重复执行。

脚本里靠退出码分流。 官方退出码表里 41 是认证、42 是输入无效(仅非交互模式)、44 是沙箱、52 是配置、53 是达到最大轮数(仅非交互模式)。这条解析崩溃不在表里——所以脚本拿到的如果是表里的码,就按表处理;不是表里的码,才考虑是这类内部错误,走重试逻辑。

版本别落太远。 这是本文重复第二遍的建议,因为对这类问题它的成功率最高。

七、要报给上游的话,怎么报才有用

这类偶发的解析崩溃,如果你能稳定复现,报上去是有价值的——因为绝大多数报告者都做不到稳定复现,能复现的报告含金量很高。

报之前先把这几样准备好:

  • 完整的报错堆栈,用 --debug 跑一次拿到(交互模式下按 F12 打开调试控制台)
  • 版本号gemini --version,以及 node -v
  • 稳定复现的最小步骤——把输入删到不能再删还能复现的程度
  • 授权方式:Google 登录、API key、还是 Vertex AI。这一条经常被漏掉,但它决定了走的是哪条服务路径

有一样不要贴:把日志、调试输出往公开仓库贴之前,先确认里面没有你的代码内容和凭证。调试输出通常包含请求体,而请求体里可能有你项目里的源码片段。这一条跟具体是哪个工具无关,是通用的习惯。

如果做不到稳定复现,报告的价值就有限了——这种情况下更实际的做法是先升级到最新版本,看问题是不是已经被修掉。

八、如果它频繁到影响干活

偶发一两次可以重试过去,如果频率高到干扰工作,有几件事可以做:

  • 降低单次任务的复杂度。请求越复杂、涉及的工具调用越多,中间出现异常响应的机会越多
  • 换授权方式试一次。Google 登录和 API key 走的路径不同,换一条能判断问题是不是绑定在某条路径上
  • 换模型试一次。不同模型的服务端行为不完全一样
  • 检查版本。这是本文第三次提到升级,因为对这类客户端解析问题,它的成功率确实最高

如果换授权、换模型、升版本都试过还是高频复现,那基本可以判定跟你的环境相关,值得按上一节的做法去报告。

九、总结

  • 这是客户端解析响应时的 JavaScript 运行时错误,不是配置、认证、网络或 prompt 的问题。
  • issue #18621 / #18622 都已关闭但没有公认解法,官方 troubleshooting 也没收录。
  • 先重试——这类偶发问题重试的成功率不低。
  • 然后升级版本,这是性价比最高的一条。
  • 别去改配置、重新登录、查网络、调 prompt——那几条是搜索结果里最常见的建议,但对这条都不对症。
  • 分清哪些报错重试有意义(这条、流中断类)、哪些重试没意义0 occurrences found for old_string)。

本文引用的 issue 编号来自 google-gemini/gemini-cli 仓库,退出码表与调试方法来自该仓库自带的 troubleshooting 文档,额度数字来自官方额度与定价页,核对日 2026-08-08。

相关阅读

想系统学会用 AI?报名体系课或加入会员,照着学、照着用。