{"record":{"id":"8218bb55458f47af","repo":"ruvnet/ruflo","slug":"run-exitcode-must-be-a-safe-integer","errorCode":null,"errorMessage":"run exitCode must be a safe integer","messagePattern":"run exitCode must be a safe integer","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/codex/src/harness/in-memory-run-receipt-reference.ts","lineNumber":29,"sourceCode":"function copy<T>(value: T): T {\n  return structuredClone(value);\n}\n\nfunction timestamp(value: string, label: string): number {\n  const parsed = Date.parse(value);\n  if (!Number.isFinite(parsed)) throw new Error(`${label} must be an ISO timestamp`);\n  return parsed;\n}\n\nfunction validateRun(run: RunEvidence): void {\n  if (!run.executionId.trim() || !run.sessionId.trim() || !run.workloadId.trim()) {\n    throw new Error('run execution, session, and workload identity are required');\n  }\n  if (!DIGEST.test(run.sourceState.sourceStateId)) throw new Error('run sourceStateId is invalid');\n  if (!DIGEST.test(run.commandDigest) || !DIGEST.test(run.evidenceDigest)) {\n    throw new Error('run command and evidence digests must be canonical sha256 values');\n  }\n  if (!Number.isSafeInteger(run.exitCode)) throw new Error('run exitCode must be a safe integer');\n  const started = timestamp(run.startedAt, 'startedAt');\n  const completed = timestamp(run.completedAt, 'completedAt');\n  if (completed < started) throw new Error('run completedAt precedes startedAt');\n  if (\n    run.buildEvidence !== undefined\n    && run.buildEvidence.sourceStateId !== run.sourceState.sourceStateId\n  ) {\n    throw new Error('build evidence belongs to a different source state');\n  }\n}\n\n/**\n * Unsigned, non-durable, content-addressed in-memory conformance ledger.\n *\n * Exact retries converge on one receipt. Reusing an execution ID with changed\n * evidence is refused rather than rewriting history. These receipts are local\n * debugging evidence and cannot authorize enforce mode or release.\n */","sourceCodeStart":11,"sourceCodeEnd":47,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/codex/src/harness/in-memory-run-receipt-reference.ts#L11-L47","documentation":"run.exitCode must satisfy Number.isSafeInteger: integers within the 2^53-1 range, including 0. The check rejects null/undefined (typical when a process died from a signal), NaN, fractional values, and integers beyond the safe range. exitCode feeds the canonical JSON receipt digest, so its numeric representation must be exact.","triggerScenarios":"recordRun with exitCode: null after child.kill(); exitCode: NaN from parseInt('SIGKILL'); exitCode: 0.5 parsed from stdout text; exitCode: 1e21 or a snowflake-sized number; exitCode left undefined in a hand-built object.","commonSituations":"Forwarding spawn/exec result exitCode without handling signal deaths; parsing exit codes from log lines; test stubs that omit exitCode; 64-bit exit-status words from other runtimes.","solutions":["Map signal deaths to the conventional 128+signal value (137 for SIGKILL, 143 for SIGTERM) so exitCode is always an integer","Default missing or non-numeric codes to a documented sentinel (e.g. 125) before recordRun","Pre-validate with Number.isSafeInteger(run.exitCode) at the call site"],"exampleFix":"// before\nreceipt.recordRun({ ..., exitCode: result.exitCode }); // null when killed by signal\n\n// after\nconst exitCode = Number.isSafeInteger(result.exitCode) ? result.exitCode : 128 + (result.signal ? signalNumber(result.signal) : 0);\nreceipt.recordRun({ ..., exitCode });","handlingStrategy":"validation","validationCode":"function toSafeExitCode(raw: number | null | undefined, signal?: string | null): number {\n  if (Number.isSafeInteger(raw)) return raw;\n  if (signal) return 128 + signalNumber(signal);\n  return 125; // documented sentinel for 'no integer exit code available'\n}","typeGuard":"function isSafeExitCode(value: unknown): value is number {\n  return typeof value === 'number' && Number.isSafeInteger(value);\n}","tryCatchPattern":"try {\n  ledger.recordRun(run);\n} catch (error) {\n  if (error instanceof Error && error.message === 'run exitCode must be a safe integer') {\n    run.exitCode = isSafeExitCode(run.exitCode) ? run.exitCode : 125;\n    ledger.recordRun(run);\n  } else throw error;\n}","preventionTips":["Normalize child-process results: map signal deaths to 128+signal before recording","Never forward raw spawn exitCode without a null/undefined check","Parse exit codes from text with parseInt and validate with Number.isSafeInteger"],"tags":["validation","exit-code","run-receipt","safe-integer"],"backgroundTag":"invalid-exit-code","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","contentChangedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}