PAYATHON 2026

NuGet Pack 报错“The user name or password is incorrect”的原因

排障赵师傅

结论

这个错误很可能来自 Windows 对 .nuspec 中 UNC 网络路径的访问失败,并非 NuGet.exe 在读取 NuGet 源的用户名和密码:

<file src="\\<FileServer>\Packages\NuGet\icons\" />

堆栈停在 System.IO.Directory.GetFiles()、PerformWildcardSearch() 和 PopulateFiles(),表明 NuGet pack 正在枚举待打包文件。构建进程无法使用当前 Windows 凭据访问共享目录,因此抛出了以下异常:

The user name or password is incorrect.
System.IO.IOException

此前出现的 error code 9009 表示系统找不到 NuGet.exe。现在 NuGet.exe 已经正常启动并进入打包阶段,重新安装通常无法解决当前问题。

为什么没有弹出用户名和密码输入框

UNC 路径通过 Windows SMB 进行身份验证。NuGet.exe 调用文件系统 API 访问目录时,Windows 会使用以下身份或凭据:

  • 启动 Visual Studio 或命令行的 Windows 用户;
  • 已经建立的 SMB 会话;
  • Windows Credential Manager 中保存的凭据;
  • 执行构建的服务账号或 CI 账号。

凭据错误、过期或当前账号没有共享权限时,文件系统 API 通常会直接返回错误,不一定弹出登录窗口。

-NonInteractive 控制 NuGet 命令、凭据提供程序等组件是否允许交互,但无法让 Directory.GetFiles() 在 SMB 共享访问失败时自动询问密码。

先验证网络路径

在运行构建的同一个 Developer Command Prompt 中执行:

whoami
dir "\\<FileServer>\Packages\NuGet\icons"

如果 dir 同样返回 “The user name or password is incorrect” 或 “Access is denied”,问题就在 Windows 网络共享访问层,与 NuGet pack 本身无关。

查看当前 SMB 连接:

net use

检查 Windows 保存的凭据:

cmdkey /list

重点检查 <FileServer>、服务器完整域名和对应 IP 地址。Windows 可能会把服务器名、完整域名和 IP 识别为不同目标,因此要以 .nuspec 中实际使用的名称为准。

清理错误的 SMB 会话

如果当前已经用错误账号连接到服务器,可以删除对应连接:

net use \\<FileServer>\IPC$ /delete

如果 net use 显示的是具体共享路径,就删除该连接:

net use "\\<FileServer>\Packages" /delete

不要直接删除所有网络连接,以免影响其他正在使用的共享资源。

然后使用正确账号重新连接。将密码参数写成 *,命令行会提示输入密码,密码也不会留在命令历史中:

net use "\\<FileServer>\Packages" /user:DOMAIN\UserName *

连接成功后再次测试:

dir "\\<FileServer>\Packages\NuGet\icons"

如果仍然失败,需要检查两层权限:

  • 共享目录的 Share Permissions;
  • 文件服务器上的 NTFS Permissions。

当前账号必须同时拥有这两层权限,才能读取目录和文件。

检查 Windows Credential Manager

打开以下位置:

Control Panel
  > Credential Manager
  > Windows Credentials

查找 <FileServer> 对应的凭据。如果其中保存了旧密码,可以删除该项,然后重新访问共享目录并输入正确账号。

也可以通过命令行删除指定凭据:

cmdkey /delete:<FileServer>

这里的目标名称必须与 cmdkey /list 中显示的名称一致。

检查 Visual Studio 使用的账号

普通命令提示符能访问共享目录,不代表 Visual Studio 中的 postbuild event 也能访问。常见原因有:

  • Visual Studio 以管理员身份运行,而网络连接建立在普通用户会话中;
  • Developer Command Prompt 和 Visual Studio 由不同账号启动;
  • 构建由 CI、计划任务或 Windows 服务执行;
  • 构建使用映射盘符,但所在会话看不到该映射。

测试 UNC 路径时,应使用实际执行构建的账号。自动构建需要为构建服务账号授予共享权限,不能依赖开发人员桌面会话中临时建立的连接。

调整 .nuspec 中的文件来源

如果这些图标属于项目资源,可以先将它们放入项目目录或本地 staging 目录,再从本地路径打包。例如:

<files>
  <file src="PackageAssets\icons\**\*" target="icons" />
</files>

本地路径通常相对于 .nuspec 的基础目录解析,具体位置应按项目目录结构确认。

如果必须直接读取网络共享,可以明确指定匹配规则:

<files>
  <file src="\\<FileServer>\Packages\NuGet\icons\*.png" target="icons" />
  <file src="\\<FileServer>\Packages\NuGet\icons\*.ico" target="icons" />
</files>

这种写法不会绕过身份验证,只会缩小文件枚举和打包的范围。

还要确认元数据引用的图标确实进入了包内。例如:

<icon>icons\Frameworks.png</icon>

该路径应与包内 target 目录和实际文件名一致。

NuGet 配置文件是否可能包含凭据

NuGet 源凭据可能保存在用户级或计算机级 NuGet.Config 中。用户级配置通常位于:

%AppData%\NuGet\NuGet.Config

配置中可能包含 packageSourceCredentials。这类凭据用于访问 NuGet HTTP 包源,例如执行 restore、push 或访问私有源。

本例的异常出现在:

System.IO.Directory.GetFiles
NuGet.Common.PathResolver.PerformWildcardSearch
NuGet.Packaging.PackageBuilder.AddFiles

这些调用都指向 .nuspec 文件路径枚举。除非构建过程还执行了其他还原操作,否则不必优先修改 NuGet.Config。

为什么堆栈不显示实际路径参数

常规 .NET 异常堆栈只记录方法签名,不记录调用参数,因此只能看到:

System.IO.Directory.GetFiles(String path, String searchPattern, SearchOption searchOption)

提高 NuGet verbosity 也不会让标准堆栈自动显示成:

System.IO.Directory.GetFiles("\\server\share\...")

可以用以下方法定位实际路径:

  1. 检查 .nuspec 中的每个 <file src="...">;
  2. 临时注释可疑的 <file> 元素,然后重新执行 pack;
  3. 在同一命令窗口中对相应路径执行 dir;
  4. 使用 Windows Process Monitor,按 Process Name is nuget.exe 过滤,查看失败的文件系统访问及其路径。

根据给出的 .nuspec,应先检查其中的 UNC 路径。

NuGet.exe 是否需要重新安装

NuGet.exe 是独立的命令行程序,一般不需要传统的安装流程。只要文件来自可信的官方发布渠道并且可以正常执行,就可以放在固定目录并加入 PATH,也可以在 postbuild event 中使用完整路径:

"C:\Program Files\NuGet\nuget.exe" pack "$(ProjectPath)" -OutputDirectory "$(TargetDir)NuGet" -IncludeReferencedProjects -Properties Configuration=$(ConfigurationName) -Verbosity detailed

这样可以防止再次出现 error code 9009,也能避免系统运行到另一个同名程序。用以下命令可以确认当前调用的文件:

where nuget
nuget help

当前错误发生在 NuGet.exe 成功启动之后,处理重点应放在 \\<FileServer>\Packages\NuGet\icons\ 的访问凭据和权限上,也可以将打包资源迁移到本地路径。

备注:内容仅供参考。