PAYATHON 2026

GitHub Actions 安装私有 npm 包时为何偶发 403?

数据阿明

结论

仅凭 403 Forbidden 不能判断请求是否被限流。题目中的错误出现在 yarn install 下载 GitHub npm registry 包文件时。403 也可能与请求身份、包访问权限或下载链接有关。几小时后恢复值得记录,但这一现象本身不足以证明发生了限流,也不能确定是某个特定服务故障。

可以先核对失败请求的响应头和发生时间,再确认 workflow 实际使用的 registry、token 和包权限。如果失败期间没有响应头、请求 ID 或其他日志,目前还无法确定根因。

先保存失败请求的证据

记录完整错误、发生时间(最好使用 UTC)、workflow 运行链接、仓库和 job,以及依赖包的名称和版本。题目中的错误包含以下下载 URL:

https://npm.pkg.github.com/download/@companyName/packageName/20.3038.0/2c900f49d1bba02598c5fe606f499054da1e31ed
Request failed "403 Forbidden"

如果能获取响应状态码、响应头和响应正文,也一并保存,并检查其中是否有请求 ID 或限流相关字段。不要打印 GITHUB_TOKEN、完整认证配置或包含凭据的 .npmrc。可以在本地临时重试同一版本,对比成功和失败时的响应,但不要把带认证头的 curl -v 输出直接上传到公开日志。

核对 job 使用的 registry 和凭据

确认 @companyName 的 scope 指向 GitHub Packages,并检查 workflow 中的权限和认证配置是否在实际运行 yarn install 的 job 中生效。下面是配置示意,认证值应从 Actions secret 或环境变量读取:

permissions:
  contents: read
  packages: read

steps:
  - uses: actions/checkout@v4
  - run: yarn install --frozen-lockfile
    env:
      NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.npmrc 通常会通过环境变量引用 token,而不是写入明文值,例如:

@companyName:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${NODE_AUTH_TOKEN}

这只是配置示例,不代表项目必须使用相同的文件位置或 Yarn 配置方式。应结合仓库实际使用的 Yarn 版本、配置文件和 workflow,确认最终生效的 registry 和认证来源。题目说明配置使用 GITHUB_TOKEN,且仓库 B 已获包读取权限。排查时仍需确认失败的 job 实际使用了这些设置,并排除其他配置覆盖它们的可能。

逐项检查访问权限

  1. 确认 packages: read 在运行安装命令的 job 或 workflow 中生效。
  2. 确认该包的访问设置仍允许仓库 B 读取,并检查仓库 A 与包之间的关联或访问配置是否符合预期。
  3. 检查失败 job 是否运行在预期的仓库和事件上下文中,以及安装步骤是否拿到了预期的 GITHUB_TOKEN。不同 job、仓库或触发方式的权限不一定相同。
  4. 对比成功与失败运行中的 lockfile、包版本、registry URL 和工作流配置。题目提到没有主动升级依赖,仍建议保存这些实际值,以排查运行环境或配置差异。

如果失败和成功运行中的这些项目确实一致,也没有凭据过期或被覆盖的迹象,可以进一步检查下载响应和 GitHub 侧记录。现有信息还不足以直接把问题归因于依赖升级。

如何判断是否与限流有关

检查失败响应是否明确包含限流信息,以及响应头是否提供了可用于识别限流状态的字段。不要因为状态码是 403,或问题几小时后消失,就认定发生了限流;仅凭 403 也无法排除限流。将失败和成功请求的时间、状态、响应头、响应正文及请求 ID(如果有)放在一起对比,查看是否有证据支持限流的判断。

如果多次复现时错误始终指向同一个下载 URL,或失败响应没有明确说明原因,可以把上述记录提交给 GitHub 支持进一步查询。提交前应删除 token、认证头和其他敏感信息。

排查顺序

  1. 保存失败运行的时间、完整错误和可获取的响应信息。
  2. 确认 job 的 packages: read、包访问授权、registry 地址和 token 注入方式。
  3. 对照一次成功运行和一次失败运行,查找请求与配置上的差异。
  4. 只有响应信息或服务端记录提供了支持,才将原因归为限流。否则应暂记为原因未明的 403,并根据请求记录继续排查。

备注:内容仅供参考。