{"record":{"id":"d38b18806cfd14c9","repo":"Yeachan-Heo/oh-my-codex","slug":"autopilot-handoff-workingdirectory-does-not-match","errorCode":null,"errorMessage":"Autopilot handoff workingDirectory does not match the selected workspace.","messagePattern":"Autopilot handoff workingDirectory does not match the selected workspace\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/cli/autopilot.ts","lineNumber":60,"sourceCode":"    if (valueFlags.has(args[i])) { i += 1; continue; }\n    if (!args[i].startsWith('--')) words.push(args[i]);\n  }\n  return words.join(' ').trim();\n}\n\nasync function jsonInput(raw: string): Promise<Record<string, unknown>> {\n  const text = raw.trim().startsWith('{') ? raw : await readFile(raw, 'utf-8');\n  const parsed = JSON.parse(text) as unknown;\n  if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) throw new Error('--handoff-json must resolve to a JSON object.');\n  return parsed as Record<string, unknown>;\n}\n\nfunction assertBoundHandoffIdentity(handoff: Record<string, unknown>, cwd: string, sessionId?: string): void {\n  if (typeof handoff.session_id === 'string' && handoff.session_id !== sessionId) {\n    throw new Error('Autopilot handoff session_id does not match the selected session.');\n  }\n  if (typeof handoff.workingDirectory === 'string' && handoff.workingDirectory !== cwd) {\n    throw new Error('Autopilot handoff workingDirectory does not match the selected workspace.');\n  }\n  handoff.session_id = sessionId;\n  handoff.workingDirectory = cwd;\n}\n\nasync function readAutopilot(cwd: string, sessionId?: string) {\n  return sessionId\n    ? readModeStateForExplicitSession('autopilot', sessionId, cwd)\n    : readModeState('autopilot', cwd);\n}\n\n/**\n * A terminalization that carried skipped gates must never read as clean success. The durable\n * marker is the machine token `complete-with-skipped-gates`; this renders the human string and\n * names each skipped gate with its missing evidence so the report is actionable.\n */\nfunction skippedGateReport(state: Record<string, unknown>): string | null {\n  if (state.completion_status !== 'complete-with-skipped-gates') return null;","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/Yeachan-Heo/oh-my-codex/blob/3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2/src/cli/autopilot.ts#L42-L78","documentation":"Thrown by assertBoundHandoffIdentity() when the handoff JSON contains a workingDirectory string that differs from the current working directory (workspace) of the autopilot command. It prevents applying a handoff bound to one workspace to another workspace.","triggerScenarios":"Calling autopilot advance from a directory different from the one where the handoff was produced, while the handoff JSON has a string workingDirectory field. Non-string/absent workingDirectory passes and is overwritten with cwd.","commonSituations":"Running the CLI from a symlinked or differently-spelled path, moving the repo directory between producing and consuming the handoff, or running the command from the repo root while the handoff was recorded in a subdirectory.","solutions":["cd into the exact working directory recorded in the handoff's workingDirectory field before running advance","Remove the workingDirectory field (or make it non-string) from the handoff so the current cwd is stamped in","Normalize both paths (resolve symlinks) if they point to the same directory but differ textually"],"exampleFix":"// before\ncd /other/dir && omx autopilot advance --handoff-json h.json  // h.json has \"workingDirectory\": \"/repo\"\n// after\ncd /repo && omx autopilot advance --handoff-json h.json","handlingStrategy":"validation","validationCode":"const h = JSON.parse(fs.readFileSync(handoffPath,'utf-8'));\nif (h.workingDirectory && path.resolve(h.workingDirectory) !== path.resolve(process.cwd())) {\n  process.chdir(path.resolve(h.workingDirectory));\n}","typeGuard":null,"tryCatchPattern":"try { await advance(handoff); } catch (e) { if (e.message.includes('workingDirectory does not match')) { process.chdir(recordedDir); await advance(handoff); } else throw e; }","preventionTips":["Run autopilot commands from a canonical (symlink-free) repo path","Strip workingDirectory from handoff files meant to be portable"],"tags":["cli","working-directory","handoff","autopilot"],"backgroundTag":"working-directory-mismatch","analyzedSha":"3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2","analyzedAt":"2026-08-27T22:18:39.783Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}