DEBUG.WIKI
V.PS:让项目靠近用户,亚太、欧洲、北美 KVM VPS
IPPeak:从目标地区访问网页,住宅代理、SEO 监测、广告验证
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国

npm ci 报 E401,检查锁文件下载地址与认证范围

私有包下载401时,对照锁文件resolved、实际下载域名和npm凭据范围,再区分入口不一致与令牌失效。

私有仓库的认证步骤已经成功,npm ci 仍在下载包时返回 E401。先看失败的完整下载地址:它可能与 .npmrc 中配置令牌的域名不同。设置了 registry,并不保证锁文件里已有的私有下载地址会自动换成这个 registry。

这个分支在 Azure Artifacts 的两种入口混用时尤其容易被忽略。开发机生成的锁文件可能指向 pkgs.dev.azure.com,CI 的认证任务却给 ACCOUNT.pkgs.visualstudio.com 配置了凭据。即使两者最终提供同一个 feed,客户端的凭据匹配仍有主机和路径范围,不能仅凭“同一仓库”判断令牌已经覆盖请求。

把失败 URL、resolved 和认证前缀放在一起看

从第一次失败的安装日志中记录包名、状态码和下载 URL,再找到锁文件中该包的 resolved。检查实际 CI 配置把认证信息放在哪个主机、哪个路径前缀下。只查看开发机的用户 .npmrc,不能证明临时 CI userconfig 也有相同内容。

以下是结构示例,不含真实凭据:

@example:registry=https://packages.example.net/team/npm/registry/
//packages.example.net/team/npm/registry/:_authToken=${NPM_TOKEN}

@example、主机和路径须替换为服务允许的实际值。环境变量由现有凭据系统提供,不要把令牌写入项目文件。这里的 registry 选择与认证前缀是两个配置项;锁文件若下载另一个主机或不属于该前缀的路径,不能假定同一配置也适用。

还要核对项目配置、用户配置、命令行与环境变量是否覆盖了预期设置。不要为排查直接把整份 .npmrc 输出到共享日志;URL 查询参数也可能含签名,保留脱敏后的主机和路径即可。

当前 npm 的锁文件规则中,registry.npmjs.org 有表示当前配置 registry 的特殊语义。这不能类推成任意私有主机都能被 --registry 替换。发现 resolved 仍指向旧私有域名时,改一个默认 registry 后继续请求旧域名,并不矛盾。

地址确实不一致时,统一受允许的 feed 入口

先确认组织允许使用哪个 feed URL,以及该 URL 对应的认证方式。如果开发和 CI 本应使用相同入口,统一项目 registry 配置,并按服务提供方的方式为实际入口准备凭据。某些服务采用 Basic 凭据,不能把上面的 Bearer token 示例无条件套过去。

另一种情况是项目准备迁移仓库入口。保存原配置与锁文件,在受控目录、明确的 npm 版本下重新解析锁文件,检查下载域名、依赖版本、完整性校验和结构变化。只想换下载入口时,不能顺带接受一批未经审核的依赖升级;也不要批量删除 integrity,或删掉锁文件让 CI 每次临时解析。

如果旧入口必须继续存在,就分别确认它仍获授权、凭据范围正确,并遵守组织的令牌权限要求。不能为消除 401 把令牌扩展到所有主机,尤其不要向来自未经核对锁文件的地址发送凭据。

历史 npm 7.5.2、7.6.0 的 Azure 流水线中出现过这组地址不一致的失败。这个环境说明可用于辨认症状,不能据此宣称当前 npm 所有 E401 都是同一缺陷,也没有充分依据给出一个“升级到某版本就必然修复”的结论。

地址一致后仍是 401,再检查凭据本身

实际请求已经落在批准的 feed 和认证范围内,却仍返回 401,应继续检查令牌是否缺失、过期、权限不足,或者认证任务与安装任务是否使用了不同配置。公开包能安装,只说明那个公开入口可用,不证明私有 feed 的认证有效。

不要把 always-auth 的历史个别处理办法当成当前版本的统一修复,也不要靠给无关 registry 填一个假 token 掩盖配置错误。安装下载时的 E401,与发布阶段的认证检查错误,不是同一个操作。

修正后在相同提交、固定工具版本的干净 CI 环境中运行原来的 npm ci,确认实际私有包下载通过,锁文件没有被安装过程改写,再完成项目构建和关键功能检查。注意 npm ci 会移除现有 node_modules;验证目录不要保留未备份的手工修改。需要撤回时一起恢复审定的配置和锁文件,令牌的恢复则沿用原凭据系统。