{"record":{"id":"81254e66f6fb75ab","repo":"Yeachan-Heo/oh-my-codex","slug":"invalid-ultragoal-plan-at-reporelative-cwd-path","errorCode":null,"errorMessage":"Invalid ultragoal plan at ${repoRelative(cwd, path)}.","messagePattern":"Invalid ultragoal plan at (.+?)\\.","errorType":"exception","errorClass":"UltragoalError","httpStatus":null,"severity":"error","filePath":"src/ultragoal/artifacts.ts","lineNumber":992,"sourceCode":"\nasync function appendLedger(cwd: string, entry: UltragoalLedgerEntry): Promise<void> {\n  await mkdir(ultragoalDir(cwd), { recursive: true });\n  const path = ultragoalLedgerPath(cwd);\n  await appendFile(path, `${JSON.stringify(entry)}\\n`);\n}\n\n/** Pure plan read: no durable writes, no migration. */\nasync function readUltragoalPlanFile(cwd: string): Promise<UltragoalPlan> {\n  const path = ultragoalGoalsPath(cwd);\n  let raw: string;\n  try {\n    raw = await readFile(path, 'utf-8');\n  } catch {\n    throw new UltragoalError(`No ultragoal plan found at ${repoRelative(cwd, path)}. Run \\`omx ultragoal create-goals ...\\` first.`);\n  }\n  const parsed = JSON.parse(raw) as UltragoalPlan;\n  if (parsed.version !== 1 || !Array.isArray(parsed.goals)) {\n    throw new UltragoalError(`Invalid ultragoal plan at ${repoRelative(cwd, path)}.`);\n  }\n  return parsed;\n}\n\n/**\n * Pure, lock-free plan read for read-only surfaces such as\n * `omx ultragoal status`: never migrates, never writes, and is therefore safe\n * for Team workers. Durable legacy migration only happens through\n * readUltragoalPlan or the mutators, under the mutation lock and authority gate.\n */\nexport async function readUltragoalPlanSnapshot(cwd: string): Promise<UltragoalPlan> {\n  return readUltragoalPlanFile(cwd);\n}\n\nfunction requiresCanonicalStatePathMigration(plan: UltragoalPlan, statePathPrefix: string): boolean {\n  return statePathPrefix !== '' && plan.codexObjective === ULTRAGOAL_AGGREGATE_CODEX_OBJECTIVE;\n}\n","sourceCodeStart":974,"sourceCodeEnd":1010,"githubUrl":"https://github.com/Yeachan-Heo/oh-my-codex/blob/3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2/src/ultragoal/artifacts.ts#L974-L1010","documentation":"The ultragoal plan JSON file exists but does not match the expected schema: it must have version === 1 and a goals array. This is a validation guard run immediately after JSON.parse, so malformed, hand-edited, or wrong-version plan files are rejected.","triggerScenarios":"Calling a plan-reading API (readUltragoalPlanFile and everything built on it) when .ultragoal goals JSON has version other than 1, a missing/non-array `goals` field, or valid JSON of the wrong shape (e.g. a plan exported from a newer/older tool version).","commonSituations":"Hand-editing the plan JSON and dropping/renaming fields; upgrading or downgrading the tooling so the on-disk version field no longer matches; merging conflicts resolved incorrectly leaving a syntactically valid but structurally wrong file; writing a custom generator that omits `goals`.","solutions":["Inspect the plan file at the path in the message: cat the JSON and confirm it has \"version\": 1 and a \"goals\": [...] array","If the file was hand-edited or mangled, regenerate it with `omx ultragoal create-goals --force`","If a version mismatch came from a tool upgrade, re-create the plan with the current tool version and re-apply goal changes","If a custom script writes the plan, make it emit {version: 1, goals: [...]}"],"exampleFix":"// before (invalid plan file)\n{ \"version\": 2, \"objectives\": [] }\n\n// after\n{ \"version\": 1, \"goals\": [ /* UltragoalItem[] */ ], \"activeGoalId\": null }","handlingStrategy":"type-guard","validationCode":"const plan = JSON.parse(await readFile(p, 'utf-8'));\nif (plan?.version !== 1 || !Array.isArray(plan.goals)) throw new Error('plan needs regeneration');","typeGuard":"function isValidUltragoalPlan(v: unknown): v is { version: 1; goals: unknown[] } { return !!v && typeof v === 'object' && (v as any).version === 1 && Array.isArray((v as any).goals); }","tryCatchPattern":"try { await readUltragoalPlan(cwd); } catch (e) { if (e instanceof UltragoalError && e.message.startsWith('Invalid ultragoal plan')) await createUltragoalPlan(cwd, { brief, force: true }); else throw e; }","preventionTips":["Never hand-edit the plan JSON; use the CLI/APIs","Pin one tool version across the team so plan schema stays consistent","Validate the shape after any merge that touches the artifact"],"tags":["ultragoal","schema-validation","json","version-mismatch"],"backgroundTag":"schema-validation-failed","analyzedSha":"3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2","analyzedAt":"2026-08-27T22:18:39.783Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}