本文要点
- 官方事故从北京时间 06:02:15 持续到 06:23:34,状态由 investigating 直接进入 resolved,影响级别为 minor。
- GitHub 没有公布具体错误码、失败比例、地区、受影响端点清单或根因,不能把所有 404、409、422 与超时都归因于这次事故。
- 先盘点调用 GET、PUT、DELETE /repos/{owner}/{repo}/contents/{path} 的任务,保存 owner、repo、path、ref、时间、HTTP 状态、request ID 与脱敏日志。
- 事故窗口内结果未知的写入或删除必须先回读目标分支与 blob SHA,不能把超时直接当失败后重复提交。
- 恢复顺序应是非关键仓库 GET、带当前 SHA 的单文件 PUT、结果回读,再逐步恢复批处理;PUT 与 DELETE 必须串行。
- 固定出口不能修复 GitHub 服务端事故;只有多个 GitHub 端点同时出现 DNS、TLS、407 或连接超时,才进入网络路径排查。
先把事故窗口说清:已解决,但没有详细根因
GitHub Status 记录显示,Degradation in repos contents API 于北京时间 2026 年 9 月 5 日 06:02:15 建立,初始状态为 investigating、影响级别为 minor;06:23:34 官方直接标记 resolved。该事件比本轮严格扫描边界早约 40 秒开始,但解决状态发生在边界之后,因此必须作为状态增量处理。
官方只确认部分 GitHub 服务出现性能影响,没有公布具体错误率、地区、受影响的 GET/PUT/DELETE 比例,也没有发布根因。不要从 incident 标题推断每个 Contents API 请求都失败,更不能把事故窗口以外的 401、403、404、409 或 422 自动归因于平台故障。
先盘点暴露面:哪些自动化真的依赖 Contents API
GitHub 官方文档把读取、创建或更新、删除仓库文件分别定义为 Contents API 端点。先搜索发布器、文档同步、配置分发、机器人和 CI 中的 /repos/{owner}/{repo}/contents/{path} 调用,记录 owner、repo、path、branch/ref、调用方法、开始时间、HTTP 状态、request ID 和重试次数。
网页能打开、git clone 正常或 Pull Requests 显示 Operational,都不能证明 Contents API 写入已成功;反过来,单次 404 也可能来自路径、ref 或权限。只对命中事故时间窗且证据相符的调用进入事故对账,其他失败继续按认证、参数、分支保护与网络分层处理。
结果未知的 PUT 与 DELETE:先回读,不要直接重放
超时或连接中断只说明客户端没有拿到确定响应,不说明服务器一定没有写入。对每个结果未知的 PUT,先 GET 目标 path 与 ref,比较返回的 blob SHA、内容哈希和预期 commit;对 DELETE 则确认路径是否仍存在,并检查目标分支最新提交。未完成对账前暂停自动重试。
更新现有文件时,官方要求在 PUT 请求中提供被替换文件的当前 sha;删除也要求目标 blob sha。使用旧 SHA 可能得到 409,参数或滥用保护可能得到 422。不要为消除报错而盲目覆盖最新内容,也不要绕过分支保护。
控制重试:幂等键、目标 SHA 与串行写入缺一不可
为每个任务保存业务幂等键、目标 branch、期望旧 SHA、新内容哈希和预期提交信息。重试前重新读取当前 SHA;如果内容已等于目标值,就把原任务标为已完成,而不是再创建一个重复提交。若分支已被他人推进,停止自动写入并重新计算差异。
GitHub 官方文档明确提醒,Create or update file contents 与 Delete a file 并行调用会冲突,必须串行执行。恢复期间进一步收紧并发和重试上限,先完成单文件闭环,再放开同仓库队列,避免服务恢复后积压请求同时冲击目标分支。
恢复验证:GET、单文件 PUT、回读、批处理
第一步在非关键仓库或测试分支执行一次 GET,确认 200、内容、ref 与 SHA。第二步基于刚读取的 SHA 做一项可回滚的单文件 PUT,记录返回 commit SHA。第三步再次 GET,确认 blob SHA、内容与分支头符合预期;最后才按少量任务、单仓库队列、全部批处理逐级恢复。
DELETE 放在最后验证,并与 PUT 串行。每一档都观察错误率、延迟、409/422、重复提交和积压深度;任一指标异常就停止扩大,保留本地已验证副本作为只读来源,并回到人工审批的单任务执行。
把错误分层:事故、权限、冲突和网络不是一回事
GET 私有内容需要 Contents read 权限,创建、更新和删除需要 Contents write;修改 .github/workflows 下文件还涉及 Workflows write。401/403 优先核对 token、仓库范围和组织策略,404 核对 owner/repo/path/ref 与资源可见性,409 核对当前 SHA 和并发写入,422 核对参数、内容与请求频率。
只有 DNS 解析失败、TLS 握手错误、代理 407、TCP 超时,或多个 GitHub API 端点都出现连接层失败时,才进入网络路径。可参考<a href="/resources/github-copilot-enterprise-proxy-ca-guide">GitHub Copilot 企业代理与 CA 指南</a>的证书与出口检查方法;固定出口只能帮助稳定复现连接,不能改变 GitHub 服务状态、token 权限或目标 SHA。
完成标准与再次停手条件
恢复完成至少要求:官方 incident 为 resolved;事故窗口任务全部有确定结果;非关键 GET 与 PUT 闭环成功;没有重复提交或意外删除;积压清零但未触发限流;分支保护、审计记录和人工审批仍然有效。只有这些条件连续稳定,才能恢复删除和大批量写入。
如果 incident 重新打开、多个仓库错误率回升、结果未知写入增加、当前 SHA 持续冲突、出现重复提交或任何删除无法解释,应立即暂停写操作。确有独立网络证据时,可<a href="/" target="_blank" rel="noopener noreferrer">访问 PuppyIP 官网</a>了解固定出口;否则继续在 GitHub 状态、权限、分支与幂等逻辑层排查。
资料来源
常见问题
GitHub repos contents API 事故现在恢复了吗?
是。GitHub Status 显示事件于北京时间 2026 年 9 月 5 日 06:23:34 resolved;事件从 06:02:15 开始,影响级别为 minor,且没有单独的 monitoring 阶段。
事故窗口内超时的 PUT 可以直接重试吗?
不应直接重试。先 GET 同一 path 与 ref,比较当前 blob SHA、内容哈希和分支最新提交;内容已落地就完成对账,分支已推进则重新计算差异。
为什么恢复后仍收到 409 或 422?
409 常与旧 SHA 或并发写入冲突有关;422 可能是参数验证失败或请求被判定为滥用。它们不能仅凭时间接近就归因于已解决的服务事故。
PUT 和 DELETE 可以并行补跑吗?
不可以。GitHub 官方文档明确说明 create/update 与 delete 并行会冲突,必须串行;恢复期还应限制同仓库并发和重试上限。
如何确认 Contents API 已可安全恢复批处理?
先在非关键仓库依次完成 GET、带当前 SHA 的单文件 PUT 和结果回读,确认没有重复提交、冲突或权限异常,再按少量任务、单仓库、全量逐级恢复。
换固定 IP 能修复 Contents API 事故吗?
不能修复 GitHub 服务端事故、token 权限或 SHA 冲突。只有多个 GitHub 端点同时出现 DNS、TLS、407 或连接超时等网络证据时,固定出口才有诊断价值。