{"record":{"id":"69e9d03efb261b7b","repo":"openai/codex-plugin-cc","slug":"claude-session-source-must-be-a-jsonl-file-sour","errorCode":null,"errorMessage":"Claude session source must be a JSONL file: ${sourcePath}","messagePattern":"Claude session source must be a JSONL file: (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"plugins/codex/scripts/lib/claude-session-transfer.mjs","lineNumber":28,"sourceCode":"function resolveUserPath(cwd, value) {\n  if (value === \"~\") {\n    return os.homedir();\n  }\n  if (String(value).startsWith(\"~/\")) {\n    return path.join(os.homedir(), String(value).slice(2));\n  }\n  return ensureAbsolutePath(cwd, value);\n}\n\nexport function resolveClaudeSessionPath(cwd, options = {}) {\n  const requestedPath = options.source || process.env[TRANSCRIPT_PATH_ENV];\n  if (!requestedPath) {\n    throw new Error(\"Could not identify the current Claude transcript. Retry with --source <path-to-claude-jsonl>.\");\n  }\n\n  const sourcePath = resolveUserPath(cwd, requestedPath);\n  if (path.extname(sourcePath) !== \".jsonl\") {\n    throw new Error(`Claude session source must be a JSONL file: ${sourcePath}`);\n  }\n\n  let source;\n  let projects;\n  try {\n    source = fs.realpathSync(sourcePath);\n    projects = fs.realpathSync(CLAUDE_PROJECTS_DIR);\n  } catch {\n    throw new Error(`Claude session file not found: ${sourcePath}`);\n  }\n  const relative = path.relative(projects, source);\n  if (relative === \"\" || relative === \"..\" || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative)) {\n    throw new Error(`Codex can import Claude sessions only from ${CLAUDE_PROJECTS_DIR}: ${source}`);\n  }\n  return source;\n}\n","sourceCodeStart":10,"sourceCodeEnd":45,"githubUrl":"https://github.com/openai/codex-plugin-cc/blob/db52e28f4d9ded852ab3942cea316258ae4ef346/plugins/codex/scripts/lib/claude-session-transfer.mjs#L10-L45","documentation":"Thrown by resolveClaudeSessionPath when the resolved source path does not have a '.jsonl' extension. Claude transcripts on disk are newline-delimited JSON (.jsonl); any other extension indicates the wrong file was supplied and would fail to parse.","triggerScenarios":"Calling resolveClaudeSessionPath with options.source pointing to a '.json', '.txt', '.log', extensionless file, or a directory. Example: { source: 'session.json' } or { source: '~/transcript.txt' }.","commonSituations":"User selects a pretty-printed '.json' export instead of the raw '.jsonl' stream. A glob matched the wrong file. The user mistyped the extension or passed a directory.","solutions":["Point --source at the actual Claude '.jsonl' transcript file.","If you only have a .json export, convert/re-export it to JSONL first.","Confirm path.extname(source) === '.jsonl' before calling.","Avoid passing directories; resolve to the specific transcript file."],"exampleFix":"// before\nresolveClaudeSessionPath(cwd, { source: '~/session.json' }) // throws\n\n// after\nresolveClaudeSessionPath(cwd, { source: '~/.claude/projects/-home-user-proj/session.jsonl' })","handlingStrategy":"validation","validationCode":"import path from 'node:path';\nfunction assertJsonl(p) {\n  if (path.extname(p) !== '.jsonl') {\n    throw new Error(`Expected a .jsonl transcript, got: ${p}`);\n  }\n}\n// call before resolveClaudeSessionPath:\n//   assertJsonl(options.source);","typeGuard":"function isJsonlPath(p) {\n  return typeof p === 'string' && p.toLowerCase().endsWith('.jsonl');\n}","tryCatchPattern":"null","preventionTips":["Filter file pickers to '*.jsonl' so users cannot select other extensions.","Convert .json exports to JSONL before importing.","Validate the extension client-side in any UI that feeds resolveClaudeSessionPath.","Glob for '*.jsonl' when auto-suggesting transcripts."],"tags":["claude-transfer","validation","file-format"],"backgroundTag":null,"analyzedSha":"db52e28f4d9ded852ab3942cea316258ae4ef346","analyzedAt":"2026-08-13T05:13:20.855Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}