{"record":{"id":"738df2e5203b9886","repo":"stablyai/orca","slug":"plain-node-entry-guard-daemon-entry-js-did-not-r","errorCode":null,"errorMessage":"[plain-node-entry-guard] daemon-entry.js did not reject an empty argv under plain Node (expected a non-zero exit and the \"${DAEMON_USAGE_PREFIX}\" error, got exit ${result.status}). stderr:\\n${stderr}","messagePattern":"\\[plain-node-entry-guard\\] daemon-entry\\.js did not reject an empty argv under plain Node \\(expected a non-zero exit and the \"(.+?)\" error, got exit (.+?)\\)\\. stderr:\\\\n(.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"config/build-plugins/plain-node-entry-guard.ts","lineNumber":219,"sourceCode":"  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 {\n    name: 'orca-plain-node-entry-guard',\n    buildStart(options: NormalizedInputOptions) {\n      assertEntryNamesAreRollupInputs(options.input)\n    },\n    writeBundle(options: NormalizedOutputOptions, bundle: OutputBundle) {","sourceCodeStart":201,"sourceCodeEnd":237,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/config/build-plugins/plain-node-entry-guard.ts#L201-L237","documentation":"The smoke-loaded daemon-entry.js exited without error, without timeout, and without a signal, but either its exit status was 0 (success) or its stderr did not contain the DAEMON_USAGE_PREFIX string ('Usage: daemon-entry'). The smoke test expects the daemon to reject an empty argv by exiting non-zero with a usage message. Getting exit 0 or a missing usage prefix means the argv parser changed its rejection behavior — it either accepts empty argv (starts the daemon) or changed its error message format.","triggerScenarios":"The argv parser in src/main/daemon/daemon-entry.ts changed its error message to not start with 'Usage: daemon-entry' (DAEMON_USAGE_PREFIX is pinned at line 119 with a 'keep in sync' comment). The parser started returning instead of throwing on empty argv, causing a clean exit 0. The parser was refactored to use a different error reporting mechanism (e.g., yargs built-in help instead of a manual throw).","commonSituations":"Switching the argv parser library (e.g., from manual parsing to commander/yargs) which changes the usage message format. Making previously-required arguments optional. Changing the error output destination from stderr to stdout (the smoke only reads stderr).","solutions":["Check src/main/daemon/daemon-entry.ts:85 — the error throw must produce a message starting with 'Usage: daemon-entry' on stderr with a non-zero exit code.","If you intentionally changed the usage message, update DAEMON_USAGE_PREFIX in plain-node-entry-guard.ts:119 to match the new prefix.","If exit status was 0, the daemon accepted empty argv — restore the rejection behavior so an accidental fork with no args fails fast instead of silently starting."],"exampleFix":"// before — daemon-entry.ts changed error format\nconsole.error('Error: missing --socket argument')\nprocess.exit(1)\n\n// after — keep the expected prefix\nthrow new Error('Usage: daemon-entry --socket <path> --token <path> [--log-file <path>]')\n// process.exit(1) follows from the uncaught throw","handlingStrategy":"validation","validationCode":"// Verify daemon-entry's usage message matches DAEMON_USAGE_PREFIX\nimport { readFileSync } from 'fs'\nfunction verifyUsagePrefix(daemonEntryPath, expectedPrefix) {\n  const source = readFileSync(daemonEntryPath, 'utf8')\n  // For source TS; for compiled JS the message is a string literal\n  if (!source.includes(expectedPrefix)) {\n    throw new Error(`daemon-entry must output '${expectedPrefix}' on empty argv — update DAEMON_USAGE_PREFIX if changed`)\n  }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep DAEMON_USAGE_PREFIX in plain-node-entry-guard.ts:119 in sync with the actual usage message in daemon-entry.ts.","Never change the error output destination from stderr to stdout — the smoke test only reads stderr.","Always exit non-zero when rejecting argv — don't just log and continue."],"tags":["build-config","smoke-test","daemon","argv-parsing","contract"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}