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\...")
可以用以下方法定位实际路径:
- 检查
.nuspec中的每个<file src="...">; - 临时注释可疑的
<file>元素,然后重新执行pack; - 在同一命令窗口中对相应路径执行
dir; - 使用 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\ 的访问凭据和权限上,也可以将打包资源迁移到本地路径。
备注:内容仅供参考。
