
notebooklm-py CLI 退出码与 JSON 错误契约自动化脚本中可靠的错误处理约定【免费下载链接】notebooklm-pyUnofficial Python API and agentic skill for Google Gemini Notebook. Full programmatic access to NotebookLMs features—including capabilities the web UI doesnt expose—via Python, CLI, and AI agents like Claude Code, Codex, and OpenClaw.项目地址: https://gitcode.com/GitHub_Trending/no/notebooklm-py本文基于 CLI exit-code 约定文档 系统讲解 notebooklm-py 命令行工具的退出码语义、JSON 错误信封error envelope以及命令级特殊契约source stale、source wait。读完后可在 Shell 与 Agent 自动化中正确区分“成功 / 可预期的命令失败 / 内部错误 / 用户中断”并利用稳定的 JSONcode字段做分支处理避免依赖随时可能变化的人类可读消息文本。核心原则退出码管控制流JSON code 管错误分类约定的基本原则只有一句话引自 原文档Use the process exit status for shell control flow. In--jsonmode, use the stable JSONcodeto distinguish error categories; human-readable messages may change.即进程退出状态exit status是面向 Shell 的控制流信号——if notebooklm ... ; then ...、set -e、CI 步骤判断都基于它--json输出中的code字段才是机器可读的、承诺稳定的错误分类依据人类可读消息文本无论 stderr 还是 JSON 的message随时可能调整脚本不应对其做字符串匹配。这一契约的集中实现位于 error_handler.py 中的handle_errors上下文管理器见 L255-L275每个 CLI 命令体都在其中执行库异常在这里被统一转换为“文本或 JSON 输出 规定退出码”的单一出口。标准退出码退出码含义0命令成功。1发生了已知的命令、输入、认证、网络、限流、配置或未找到错误。2未预期的内部错误或 Click 报告的 argv 解析错误。130用户中断了命令Ctrl-C / SIGINT。“已知的库错误”Known library errors一律退出1。在 JSON 输出中常见的稳定code包括AUTH_ERROR、CONFIG_ERROR、NETWORK_ERROR、NOT_FOUND、RATE_LIMITED和VALIDATION_ERROR未处理的异常则是UNEXPECTED_ERROR且退出2。异常与错误码的中央映射表handle_errors内部按异常类型分派到固定分支这张表就是自动化脚本可以依赖的“中央映射”异常或失败JSONcode退出码任何被标记unconfirmedTrue的已发出异常UNCONFIRMED_WRITE继承所匹配分支已处理的库错误为1意外异常为2RateLimitErrorRATE_LIMITED1AuthErrorAUTH_ERROR1ValidationErrorVALIDATION_ERROR1ConfigurationErrorCONFIG_ERROR1NetworkErrorNETWORK_ERROR1NotebookLimitErrorNOTEBOOK_LIMIT1ArtifactTimeoutErrorARTIFACT_TIMEOUT1NotFoundError及各领域*NotFoundErrorNOT_FOUND1其他NotebookLMErrorNOTEBOOKLM_ERROR1KeyboardInterruptCANCELLED130未处理的ExceptionUNEXPECTED_ERROR2UNCONFIRMED_WRITE覆盖规则的底层原因UNCONFIRMED_WRITE覆盖优先于按异常类型的映射。它的语义是该写操作可能已经提交成功调用方在重试之前应先核对reconcile实际状态否则可能造成重复写入。从源码结构看这条覆盖是刻意放在所有分支的公共漏斗emit里的error_handler.py L300-L334幂等性探测无法确认一个 create 是否落库时对应 issue #2220异常会被打上unconfirmed标记即使它同时是RateLimitError分支会给“Retry after Ns”的文案、AuthError“重新登录再试”或NetworkError“再试一次”emit也会替换而不是追加消息并在 JSON 中剥离retry_after字段——因为这些分支自带的“去重试”指令正是该标记要阻止的动作覆盖后的固定文案明确写道“Check the notebook (or the notebooks source list) before retrying — retrying blind can create a duplicate.”见 L114-L123。对脚本的含义是只要 JSON 中出现code: UNCONFIRMED_WRITE通常还伴随unconfirmed: true和hint字段正确动作是查询状态而不是重试。NOT_FOUND信封中的资源 ID各领域的*NotFoundErrorNotFoundError的具体子类如SourceNotFoundError、NotebookNotFoundError等都会把缺失资源的 ID 带上。中央处理器会把这些 ID 以原生键名 通用id键双份写进 JSON例如{source_id: ..., id: ...}这样自动化代码无需知道具体子类型就能读取 ID。该逻辑在 error_handler.py L69-L99 的_not_found_extra中实现覆盖notebook_id、source_id、artifact_id、note_id、mind_map_id、label_id、collection_id七类属性。Click 校验错误解析期 vs 命令体内这是映射表之外最容易踩坑的一格约定文档给出了两条规则解析期parse-time的 Click 用法/参数失败例如未知 flag、缺失必填参数、非法的--limit在--json下走VALIDATION_ERROR信封但保留 Click 自己的退出码usage error 为2其余为该 Click 异常的退出码命令体内post-parse抛出的 Click 校验错误走VALIDATION_ERROR且退出1。从源码结构看--json下解析期错误之所以还能发出 JSON 信封是因为根命令组在 Click 之上又开了一道更高边界grouped.py 中的根组以非独立模式运行 Click 的main从而能捕获解析期本应由 Click 自己渲染的ClickException并在原始 argv 含--json时改发VALIDATION_ERROR信封。该设计决策完整记录在 ADR-0015其中明确解析期包装只改变输出通道JSON 到 stdout而非 usage 文本到 stderr不改变退出码——UsageError/BadParameter仍退出2基础ClickException退出1而 post-parse 路径经由handle_errors则标准化为退出1。因此source add-research之类的 flag 互斥冲突在--json下会给出{error: true, code: VALIDATION_ERROR, ...}并退出2而无--json时则是 Click 原生Usage: ... / Error: ...文本写到 stderr见 source_cmd.py L778 附近注释 对 ADR-0015 §2 契约的引用。JSON 错误信封格式支持--json的命令在出错时同时做两件事向 stdout 输出错误 JSON并以非零状态退出。输出由_output_error统一生成文本模式才写 stderr{ error: true, code: RATE_LIMITED, message: Error: Rate limited. Retry after 30s., retry_after: 30 }要点把code当作机器可读的分类message仅作人读额外字段是命令与错误特定的例如RATE_LIMITED携带retry_after秒数来自 error_handler.py L364-L378NOT_FOUND可携带id及资源专属 ID 字段ARTIFACT_TIMEOUT携带notebook_id、task_id、timeout_seconds、status_history等生成诊断字段L410-L429用户中断在--json下同样可解析emit_cancelled_and_exit发出{error: true, code: CANCELLED, message: Cancelled by user, resume_hint: ...}后以SystemExit(130)结束128 SIGINT 信号 2长轮询命令如--wait会附带resume_hint提示如何恢复L205-L251。Shell 中的标准用法原文档给出的控制流模板可直接复制notebooklm ask -n $NOTEBOOK_ID Summarize --json out.json case $? in 0) ;; # success 1) jq -r .code out.json 2 ;; # expected command failure 2) echo invalid invocation or CLI bug 2 ;; 130) echo cancelled 2 ;; esac注意130分支case必须显式处理它否则 Ctrl-C 会被误判为未定义行为。命令级契约source stale默认退出 0--exit-on-stale才反转默认情况下notebooklm source stale ID只要新鲜度检查本身成功就退出0——无论结果是 stale 还是 fresh。分支判断应该看 JSON 输出中的stale/fresh字段{source_id: ..., notebook_id: ..., stale: true, fresh: false}--exit-on-stale开启的是旧的谓词形式0表示 stale1表示 fresh。由于在该选项下1同时也被普通错误使用无人值守自动化中不能把每个1都当成 “fresh”——约定文档明确建议“需要这种区分时优先使用默认模式 JSON”。实现与文档一一对应_render_source_stale_result中JSON 路径在exit_on_staleTrue时执行exit_with_code(0 if result.stale else 1)文本路径则分别为 fresh 时exit_with_code(1)、stale 时exit_with_code(0)未加该选项时函数直接返回进程以0结束。其 docstring 还保留了旧脚本仍能工作的动机说明so the shell idiom if notebooklm source stale --exit-on-stale ID; then refresh; fi keeps working for scripts written against the prior default.source wait有意设计的三态退出码notebooklm source wait ID的契约是刻意的三分支因为2在这里被重新赋予了“可恢复的超时”语义而非“内部故障”退出码含义0源已就绪ready。1源未找到或处理失败。2在源就绪前超时。这一契约直接写进了命令自身的 docstringsource_cmd.py L977-L983Polls until the source is ready or fails. Exit code 0ready, 1missing or processing failed, 2timeout. Spawn this in a subagent after source add returns so the main conversation can continue.该命令默认--timeout 120、--interval 1来自wait_polling_options(default_timeout120, default_interval1)装饰器L974。对 Agent 场景的建议是在source add返回后把source wait交给子进程执行主流程继续推进2出现时直接重新发起同一source wait其轮询上下文自带resume_hint: notebooklm source wait id因为源没有独立的 poll 子命令。Not-found 行为迁移约定文档特别标注了行为变更source get、artifact get和note get现在对缺失资源退出1而不是旧的成功退出码。在--json下它们发出code: NOT_FOUND附带上文所述的id字段文本模式下错误消息写到 stderr。从源码结构看这一约定由handle_errors中专门位于通用NotebookLMError兜底之前的NotFoundError分支保障error_handler.py L430-L458所有具体*NotFoundError都派生自NotFoundError该分支保证缺失资源得到类型化的NOT_FOUND信封而不是笼统的NOTEBOOKLM_ERRORverbose模式下还会附带method_id并可基于近似的candidates给出 “did you mean” 提示。迁移建议与原文档一致依赖旧成功退出状态的脚本应改为处理退出1并在需要时检查 JSONcode以区分“资源缺失”与其他1类错误。如何在仓库中验证这份契约关注点证据位置退出码与 JSON code 的中央映射error_handler.py 的handle_errors/_output_error解析期--json下 Click 异常的VALIDATION_ERROR包装grouped.py、ADR-0015契约回归测试tests/unit/cli/test_json_validation_contract.py断言 stdout 信封、stderr 为空、退出码保持source stale退出策略_source_render.py L463-L505source wait三态契约source_cmd.py L971-L1010各UsageError位点的内联标记受守护测试审查见 error_handler.py L33-L38 注释相关文档CLI 参考配置说明故障排查【免费下载链接】notebooklm-pyUnofficial Python API and agentic skill for Google Gemini Notebook. Full programmatic access to NotebookLMs features—including capabilities the web UI doesnt expose—via Python, CLI, and AI agents like Claude Code, Codex, and OpenClaw.项目地址: https://gitcode.com/GitHub_Trending/no/notebooklm-py创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考