{"record":{"id":"6bc213c11ef84143","repo":"stablyai/orca","slug":"plain-node-entry-guard-daemon-entry-js-failed-to","errorCode":null,"errorMessage":"[plain-node-entry-guard] daemon-entry.js failed to load under plain Node:\\n${stderr}","messagePattern":"\\[plain-node-entry-guard\\] daemon-entry\\.js failed to load under plain Node:\\\\n(.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"config/build-plugins/plain-node-entry-guard.ts","lineNumber":214,"sourceCode":"        `${result.error.message}`\n    )\n  }\n  // Almost always means the daemon stopped rejecting an empty argv and started\n  // listening instead.\n  if (result.timedOut) {\n    throw new Error(\n      `[plain-node-entry-guard] daemon-entry.js did not exit within ${timings.timeoutMs}ms on an ` +\n        `empty argv under plain Node, so the smoke killed it.`\n    )\n  }\n  if (result.signal) {\n    throw new Error(\n      `[plain-node-entry-guard] daemon-entry.js was killed by ${result.signal} under plain Node.`\n    )\n  }\n  const stderr = result.stderr\n  if (/Cannot find module|MODULE_NOT_FOUND/.test(stderr)) {\n    throw new Error(\n      `[plain-node-entry-guard] daemon-entry.js failed to load under plain Node:\\n${stderr}`\n    )\n  }\n  if (result.status === 0 || !stderr.includes(DAEMON_USAGE_PREFIX)) {\n    throw new Error(\n      `[plain-node-entry-guard] daemon-entry.js did not reject an empty argv under plain Node ` +\n        `(expected a non-zero exit and the \"${DAEMON_USAGE_PREFIX}\" error, got exit ` +\n        `${result.status}). stderr:\\n${stderr}`\n    )\n  }\n}\n\nexport function createPlainNodeEntryGuardPlugin(\n  smokeTimings: SmokeTimings = DEFAULT_SMOKE_TIMINGS\n): Plugin {\n  let daemonOutputDir: string | undefined\n\n  return {","sourceCodeStart":196,"sourceCodeEnd":232,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/config/build-plugins/plain-node-entry-guard.ts#L196-L232","documentation":"After the smoke-loaded daemon-entry.js process exits, its stderr is scanned for `/Cannot find module|MODULE_NOT_FOUND/`. If matched, this error fires with the full stderr. This catches gross load failures — an unresolved `require()` in the daemon's module graph under plain Node. The comment clarifies this is NOT the electron regression guard (that's the static scan in error [1]); this only catches missing runtime dependencies that fail to resolve at load time.","triggerScenarios":"A runtime dependency that the daemon graph require()s is not available under plain Node — e.g., a package that was externalized by Rollup but whose node_modules copy is missing from the output directory, or a native addon (.node file) that can't be loaded. The MODULE_NOT_FOUND can also come from a subpath import that resolves under Electron's module system but not under plain Node.","commonSituations":"Adding a new dependency to daemon-entry's import graph without adding it to the packaged node_modules. A dependency that worked in dev (where node_modules is present) but fails in the build output directory where only specific packages are copied. Native module path resolution differences between Electron and plain Node.","solutions":["Read the stderr in the error message — it names the exact module that couldn't be found.","If it's a bare package specifier (e.g., 'node-pty'), ensure it's listed in PACKAGED_RUNTIME_PACKAGE_ROOTS in packaged-runtime-node-modules.cjs so it gets copied to resources/node_modules.","If it's a relative path or subpath, check that the asarUnpack config in electron-builder.config.cjs includes the directory containing that file.","Run the smoke test manually: `node out/main/daemon-entry.js` from the build output directory to reproduce and debug interactively."],"exampleFix":"// before — daemon-entry imports a new dep not in packaged runtime roots\nconst { foo } = require('new-package')\n\n// after — add to PACKAGED_RUNTIME_PACKAGE_ROOTS in packaged-runtime-node-modules.cjs\nconst PACKAGED_RUNTIME_PACKAGE_ROOTS = [\n  // ...existing entries...\n  'new-package'\n]","handlingStrategy":"validation","validationCode":"// Verify all externalized deps resolve under plain Node before packaging\nimport { spawnSync } from 'child_process'\nimport { join } from 'path'\nfunction verifyDaemonGraphResolves(outputDir) {\n  const result = spawnSync(process.execPath, [join(outputDir, 'daemon-entry.js')], {\n    timeout: 5000, stdio: 'pipe'\n  })\n  if (/Cannot find module|MODULE_NOT_FOUND/.test(result.stderr.toString())) {\n    throw new Error(`Unresolved require in daemon graph:\\n${result.stderr}`)\n  }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["After adding a new dependency to daemon-entry's import graph, run `node out/main/daemon-entry.js` locally to verify it loads.","Keep PACKAGED_RUNTIME_PACKAGE_ROOTS in sync with the daemon's external dependencies.","Ensure asarUnpack includes all directories the daemon needs to require from at runtime."],"tags":["build-config","smoke-test","daemon","module-resolution","node-modules"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}