环境
| 项目 |
值 |
| 平台 |
Windows 11(build 10.0.26200)x64 |
| Node |
v24.21.0 |
| npm |
11.19.0 |
@patodo/localapp |
0.2.1 |
| native adapter |
runtime/native/win32-x64/localapp-native.exe,sha256 2c025476c800ebcece0a5cc158928c67a30b2b6529ccd1c3508a475f9fce12d1 |
概要
localapp server start 在 Windows 上必定失败:
{"error":{"code":"native_adapter_failed","message":"The LocalApp native adapter command failed"}}
之后 localapp server status 永远返回:
{"error":{"code":"daemon_unreachable","message":"The LocalApp daemon is unreachable"}}
根因是 localapp-native.exe --register --config <path> 在成功写完 localapp:// 注册表项之后,以 0xC0000374(STATUS_HEAP_CORRUPTION)崩溃退出。CLI 仅依据退出码判定,于是把这条命令当成失败并中止流程,manager.install()(写 service/windows-user-task.json)根本没有执行,daemon 因此从未被安装。
复现步骤
npm install --global @patodo/localapp
localapp server start
# {"error":{"code":"native_adapter_failed","message":"The LocalApp native adapter command failed"}}
localapp server status
# {"error":{"code":"daemon_unreachable","message":"The LocalApp daemon is unreachable"}}
最小化复现(此时 %LOCALAPPDATA%\LocalApp\native-bridge.json 已由 CLI 写好):
$exe = "$env:LOCALAPPDATA\LocalApp\releases\<version>-<artifactDigest>\runtime\native\win32-x64\localapp-native.exe"
$cfg = "$env:LOCALAPPDATA\LocalApp\native-bridge.json"
$p = Start-Process -FilePath $exe -ArgumentList '--register','--config',$cfg -Wait -PassThru
$p.ExitCode # -1073740940 (0xC0000374)
触发条件定位
决定是否崩溃的是 config 文件的位置(是否位于 LocalApp 支持目录内),而不是它的内容:
--config 指向 |
结果 |
%LOCALAPPDATA%\LocalApp\native-bridge.json(CLI 写的真实配置) |
崩溃 -1073740940,3/3 稳定复现 |
%TEMP%\latest\minimal.json(内容相同,放在别处) |
退出码 1,不崩溃 |
%LOCALAPPDATA%\LocalApp\test-bridge.json(同样的最小内容,放进支持目录) |
崩溃 -1073740940 |
C:\nonexistent\nope.json |
退出码 1,不崩溃 |
--register(不带 --config) |
退出码 1,不崩溃 |
其他子命令均正常:--permission-state、--request-permission 都返回 granted 且退出码 0。
崩溃点在注册表写入之后:先删除 HKCU\Software\Classes\localapp,再执行 --register --config,该键会被正确重建(默认值指向 localapp-native.exe --scheme --config "..." "%1"),然后进程才崩溃。也就是说注册动作本身成功了,出问题的是成功路径之后的代码(很可能是退出前的清理/释放路径)。
崩溃证据
Windows 应用程序事件日志(事件 ID 1000,Provider Application Error):
出错应用程序名称: localapp-native.exe,版本: 0.0.0.0,时间戳: 0x6a86787e
出错模块名称: ntdll.dll,版本: 10.0.26100.9444,时间戳: 0x6bdf03ca
异常代码: 0xc0000374
错误偏移: 0x0000000000117eb5
0x117eb5 在多次运行中完全一致,是确定性崩溃。0xC0000374 为堆损坏,通常由堆元数据被越界写坏后、由 ntdll 在后续分配/释放时检出。
影响范围
localapp server start 在 Windows 上不可用。
- daemon 从未安装:
%LOCALAPPDATA%\LocalApp\service\windows-user-task.json 不存在,logs\、run\ 为空目录。
- 依赖本地 daemon 的后续流程全部无法进入:本地 Server、
localapp login http://127.0.0.1:<port>、localapp dev、app install --target local。
Server 本体没有问题。 直接启动 runtime 中的 server 可正常到达 ready:
$ node runtime/server/bin/server.mjs start --data-dir "C:\Users\p\AppData\Local\LocalApp\data" --host 127.0.0.1 --port 0
{"type":"starting","workerPid":17704}
Content storage: local filesystem (C:\Users\p\AppData\Local\LocalApp\data) — MinIO unavailable
{"type":"ready","listenUrl":"http://127.0.0.1:53111","url":"http://127.0.0.1:53111","workerPid":17704,"setupUrl":"http://127.0.0.1:53111/setup?token=..."}
所以问题被完全隔离在 win32 native adapter 的 --register 路径上。
附带发现:localapp server run 在 Windows 上也无法按文档直接使用
README 把 localapp server run 描述为“以前台模式运行同一 Server,适合容器和服务管理器”。在 Windows 上不带额外环境变量执行它必定失败:
$ localapp server run
{"error":{"code":"command_failed","message":"LocalApp command failed"}}
原因在 bundle 内的 bin/localapp.mjs:29722,spawnOwnedProcess() 在 win32 上要求能构造 Job Object adapter:
const windowsAdapter = options2.windowsAdapter ?? createWindowsProcessTreeAdapterFromEnvironment();
if (windowsAdapter === void 0) {
throw new Error("Windows process-tree adapter is unavailable; refusing to spawn without atomic Job Object ownership");
}
而 windowsNativeExecutableFromEnvironment() 只从 process.env.LOCALAPP_RELEASE_PATH 推导 exe 路径,该变量仅由 runtime/bootstrap/localapp-daemon-bootstrap.mjs 设置。用户在 shell 里按 README 直接运行 localapp server run 时它必然为空,于是抛出的是普通 Error 而非 LocalAppLifecycleError,绕过结构化错误分支,被顶层 catch-all 归为 command_failed,丢失了真实原因。
显式设置该变量后即可正常前台启动(已用 release 目录验证):
$ LOCALAPP_RELEASE_PATH="C:\...\releases\0.2.1-<digest>" localapp server run
{"type":"starting","workerPid":23260}
{"type":"ready","listenUrl":"http://127.0.0.1:64586", ...}
若“必须经由 daemon bootstrap 调用”是有意设计,建议 server run 至少返回可读的错误码(例如 native_adapter_unsupported/单独的错误码,而不是 command_failed),并在 README 中说明该前置条件。
环境
@patodo/localappruntime/native/win32-x64/localapp-native.exe,sha2562c025476c800ebcece0a5cc158928c67a30b2b6529ccd1c3508a475f9fce12d1概要
localapp server start在 Windows 上必定失败:{"error":{"code":"native_adapter_failed","message":"The LocalApp native adapter command failed"}}之后
localapp server status永远返回:{"error":{"code":"daemon_unreachable","message":"The LocalApp daemon is unreachable"}}根因是
localapp-native.exe --register --config <path>在成功写完localapp://注册表项之后,以0xC0000374(STATUS_HEAP_CORRUPTION)崩溃退出。CLI 仅依据退出码判定,于是把这条命令当成失败并中止流程,manager.install()(写service/windows-user-task.json)根本没有执行,daemon 因此从未被安装。复现步骤
最小化复现(此时
%LOCALAPPDATA%\LocalApp\native-bridge.json已由 CLI 写好):触发条件定位
决定是否崩溃的是 config 文件的位置(是否位于 LocalApp 支持目录内),而不是它的内容:
--config指向%LOCALAPPDATA%\LocalApp\native-bridge.json(CLI 写的真实配置)-1073740940,3/3 稳定复现%TEMP%\latest\minimal.json(内容相同,放在别处)%LOCALAPPDATA%\LocalApp\test-bridge.json(同样的最小内容,放进支持目录)-1073740940C:\nonexistent\nope.json--register(不带--config)其他子命令均正常:
--permission-state、--request-permission都返回granted且退出码 0。崩溃点在注册表写入之后:先删除
HKCU\Software\Classes\localapp,再执行--register --config,该键会被正确重建(默认值指向localapp-native.exe --scheme --config "..." "%1"),然后进程才崩溃。也就是说注册动作本身成功了,出问题的是成功路径之后的代码(很可能是退出前的清理/释放路径)。崩溃证据
Windows 应用程序事件日志(事件 ID 1000,Provider
Application Error):0x117eb5在多次运行中完全一致,是确定性崩溃。0xC0000374为堆损坏,通常由堆元数据被越界写坏后、由 ntdll 在后续分配/释放时检出。影响范围
localapp server start在 Windows 上不可用。%LOCALAPPDATA%\LocalApp\service\windows-user-task.json不存在,logs\、run\为空目录。localapp login http://127.0.0.1:<port>、localapp dev、app install --target local。Server 本体没有问题。 直接启动 runtime 中的 server 可正常到达 ready:
所以问题被完全隔离在 win32 native adapter 的
--register路径上。附带发现:
localapp server run在 Windows 上也无法按文档直接使用README 把
localapp server run描述为“以前台模式运行同一 Server,适合容器和服务管理器”。在 Windows 上不带额外环境变量执行它必定失败:原因在 bundle 内的
bin/localapp.mjs:29722,spawnOwnedProcess()在 win32 上要求能构造 Job Object adapter:而
windowsNativeExecutableFromEnvironment()只从process.env.LOCALAPP_RELEASE_PATH推导 exe 路径,该变量仅由runtime/bootstrap/localapp-daemon-bootstrap.mjs设置。用户在 shell 里按 README 直接运行localapp server run时它必然为空,于是抛出的是普通Error而非LocalAppLifecycleError,绕过结构化错误分支,被顶层 catch-all 归为command_failed,丢失了真实原因。显式设置该变量后即可正常前台启动(已用 release 目录验证):
若“必须经由 daemon bootstrap 调用”是有意设计,建议
server run至少返回可读的错误码(例如native_adapter_unsupported/单独的错误码,而不是command_failed),并在 README 中说明该前置条件。