{"record":{"id":"ec3f7ef49c2f0ef9","repo":"can1357/oh-my-pi","slug":"codex-session-info-id-at-info-path-is-empty","errorCode":null,"errorMessage":"Codex session ${info.id} at ${info.path} is empty or malformed","messagePattern":"Codex session (.+?) at (.+?) is empty or malformed","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/session/codex-session-store.ts","lineNumber":551,"sourceCode":"\t\t\t\tmodified,\n\t\t\t});\n\t\t}\n\t\tsessions.sort(\n\t\t\t(left, right) => right.modified.getTime() - left.modified.getTime() || left.id.localeCompare(right.id),\n\t\t);\n\t\treturn sessions;\n\t}\n\n\t/** Converts one Codex rollout into a non-persistent OMP session. */\n\tasync load(info: ForeignSessionInfo): Promise<SessionManager> {\n\t\tif (info.source !== \"codex\") throw new Error(`Cannot load ${info.source} session with CodexSessionStore`);\n\t\tlet records: Record<string, unknown>[];\n\t\ttry {\n\t\t\trecords = await readJsonLines(info.path);\n\t\t} catch (error) {\n\t\t\tthrow new Error(`Unable to read Codex session ${info.id} at ${info.path}`, { cause: error });\n\t\t}\n\t\tif (records.length === 0) throw new Error(`Codex session ${info.id} at ${info.path} is empty or malformed`);\n\n\t\tconst metadata = records.find(record => record.type === \"session_meta\" && isRecord(record.payload));\n\t\tconst cwd =\n\t\t\tmetadata && isRecord(metadata.payload) ? (stringField(metadata.payload, \"cwd\") ?? info.cwd) : info.cwd;\n\t\tconst manager = SessionManager.inMemory(cwd);\n\t\tconst canonical = canonicalTexts(records);\n\t\tconst converted: ConvertedRecord[] = [];\n\t\tconst toolNames = new Map<string, string>();\n\t\tlet model = \"codex\";\n\t\tlet fallbackTimestamp = info.created.getTime();\n\t\tlet title = info.title;\n\n\t\tfor (const record of records) {\n\t\t\tconst timestamp = timestampMillis(record.timestamp, fallbackTimestamp);\n\t\t\tfallbackTimestamp = Math.max(fallbackTimestamp + 1, timestamp);\n\t\t\tif (!isRecord(record.payload)) continue;\n\t\t\tlet item: ConvertedRecord | undefined;\n\t\t\tif (record.type === \"turn_context\") {","sourceCodeStart":533,"sourceCodeEnd":569,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/session/codex-session-store.ts#L533-L569","documentation":"CodexSessionStore.load() successfully read the rollout file but readJsonLines yielded zero records, meaning the file is empty or every line failed parsing. Thrown to distinguish 'readable but no usable content' from a hard read failure.","triggerScenarios":"Calling load(info) on a zero-byte rollout file, a file containing only blank lines, or a file whose lines are all malformed JSON so readJsonLines returns an empty array.","commonSituations":"Codex created the session file but crashed before writing the session_meta line; disk-full left a stub file; a sync tool synced an empty placeholder; the wrong file was passed as info.path.","solutions":["Check file size (ls -l info.path) — a 0-byte file means Codex never wrote the session","Re-run the Codex session to regenerate a real rollout, then re-list and load","Remove the empty/stub file so stale listings stop offering it","Point info.path at the actual rollout file if the wrong path was passed"],"exampleFix":"// before\nconst manager = await codexStore.load(info);\n// after\nconst stat = await fs.stat(info.path);\nif (stat.size === 0) throw new Error(`Codex rollout is empty: ${info.path}`);\nconst manager = await codexStore.load(info);","handlingStrategy":"validation","validationCode":"import * as fs from \"node:fs\";\nexport function isNonEmptyCodexRollout(path: string): boolean {\n  try {\n    const content = fs.readFileSync(path, 'utf8');\n    return content.split('\\n').some(line => line.trim().length > 0);\n  } catch {\n    return false;\n  }\n}","typeGuard":"function isEmptyOrMalformedCodexSession(err: unknown): boolean {\n  return err instanceof Error && /is empty or malformed$/.test(err.message);\n}","tryCatchPattern":null,"preventionTips":["Check the rollout has content before offering a session for resume","Delete zero-byte stub files left by crashed Codex runs","Pass info.path from store.list() output rather than constructing paths by hand"],"tags":["session","parsing","codex","empty-file"],"backgroundTag":"session-file-corrupt","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}