{"record":{"id":"2e03f0b47b2a0249","repo":"santifer/career-ops","slug":"openai-eval-mjs-exited-res-status-res-stder","errorCode":null,"errorMessage":"openai-eval.mjs exited ${res.status}: ${(res.stderr || '').slice(0, 200)}","messagePattern":"openai-eval\\.mjs exited (.+?): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"eval-golden.mjs","lineNumber":159,"sourceCode":"    // path separators, or the fixture lands in a phantom subdirectory. Sanitize\n    // to a flat filename — record fixtures under the same sanitized name.\n    const fixture = join(fixtureDir, `${testCase.id}__${fixtureModelId(model)}.txt`);\n    if (!existsSync(fixture)) {\n      throw new Error(`missing replay fixture: ${fixture} — record it or run --live`);\n    }\n    return readFileSync(fixture, 'utf8');\n  }\n\n  // live: write the JD to a temp file and run the existing evaluator.\n  const dir = mkdtempSync(join(tmpdir(), 'eval-golden-'));\n  try {\n    const jdFile = join(dir, 'jd.txt');\n    writeFileSync(jdFile, testCase.jd);\n    const res = spawnSync(process.execPath,\n      [join(ROOT, 'openai-eval.mjs'), '--file', jdFile, '--model', model, '--no-save'],\n      { encoding: 'utf8', env: process.env, timeout: 360000 });\n    if (res.status !== 0) {\n      throw new Error(`openai-eval.mjs exited ${res.status}: ${(res.stderr || '').slice(0, 200)}`);\n    }\n    return res.stdout || '';\n  } finally {\n    rmSync(dir, { recursive: true, force: true });\n  }\n}\n\n/**\n * Median of a numeric array (0 for an empty array).\n *\n * @param {number[]} xs - Values to summarize.\n * @returns {number} The median value.\n */\nfunction median(xs) {\n  if (xs.length === 0) return 0;\n  const s = [...xs].sort((a, b) => a - b);\n  const mid = Math.floor(s.length / 2);\n  return s.length % 2 ? s[mid] : (s[mid - 1] + s[mid]) / 2;","sourceCodeStart":141,"sourceCodeEnd":177,"githubUrl":"https://github.com/santifer/career-ops/blob/aac998c7ed7248ea853b720ceeb1fdbeb322fc5d/eval-golden.mjs#L141-L177","documentation":"In live mode, getCompletion shells out to openai-eval.mjs via spawnSync with a 6-minute timeout, writing the JD to a temp file. If the child process exits with a non-zero status, this error propagates its exit code plus up to 200 characters of stderr, surfacing whatever the underlying evaluator failed on (auth, rate limit, bad model name, crash).","triggerScenarios":"Calling getCompletion (or eval-golden.mjs) with --live when openai-eval.mjs exits non-zero: invalid/missing API key, network failure, rate limit or provider 5xx, unsupported --model value, unhandled exception inside openai-eval.mjs, or the 360000ms timeout being hit (spawnSync reports a non-null/failed status).","commonSituations":"Expired or unset OPENAI/DEEPSEEK API key in CI secrets; provider outage or 429 during a batch run; model id typo after a provider rename; IPv4/VPN/network restrictions in sandboxed CI blocking outbound API calls; child crashed due to a malformed JD file.","solutions":["Run openai-eval.mjs directly with the same --file/--model flags to see the full stderr beyond the 200-char truncation.","Check API credentials (env var set, not expired, has quota) — the most common cause is missing/invalid key.","Retry after a provider 429/5xx; add backoff or run the batch when rate limits reset.","Validate the --model value is supported by openai-eval.mjs (provider rename? typo?).","If the timeout was hit (6 min), check network egress from your environment or use replay mode with a recorded fixture."],"exampleFix":"# before: opaque failure inside a batch run\nnode eval-golden.mjs --live\n# Error: openai-eval.mjs exited 1: Error: 401 Unauthorized...\n\n# after: reproduce directly to see full stderr, fix the key\nOPENAI_API_KEY=sk-... node openai-eval.mjs --file jd.txt --model deepseek/deepseek-chat --no-save\nnode eval-golden.mjs --live","handlingStrategy":"retry","validationCode":"import { spawnSync } from 'node:child_process';\nconst probe = spawnSync(process.execPath, [join(ROOT, 'openai-eval.mjs'), '--help'], { encoding: 'utf8' });\nif (probe.error || probe.status !== 0) console.error('openai-eval.mjs not runnable here:', probe.stderr);","typeGuard":null,"tryCatchPattern":"try {\n  return getCompletion(testCase, model, { mode: 'live' });\n} catch (err) {\n  if (err.message.includes('openai-eval.mjs exited')) {\n    if (/429|rate/i.test(err.message)) { await sleep(backoff); return retry(); }\n    if (/401|403/i.test(err.message)) console.error('Check API key before retrying');\n  }\n  throw err;\n}","preventionTips":["Verify API credentials and quota before starting a live batch run","Prefer replay mode in CI; reserve --live for deliberate fixture recording","Run openai-eval.mjs standalone first when debugging — it prints full stderr without the 200-char truncation","Add retry-with-backoff around live calls to absorb transient 429/5xx","Ensure CI has network egress to the provider before scheduling live evals"],"tags":["subprocess","api","live-mode","exit-code"],"backgroundTag":"upstream-api-error","analyzedSha":"aac998c7ed7248ea853b720ceeb1fdbeb322fc5d","analyzedAt":"2026-09-16T06:35:29.214Z","contentChangedAt":"2026-09-16T06:35:29.214Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}