{"record":{"id":"3ea2cd66dd5a6825","repo":"Hmbown/CodeWhale","slug":"codewhale-session-contains-no-journal-entries-or-messages-3ea2cd","errorCode":null,"errorMessage":"Codewhale session contains no journal entries or messages.","messagePattern":"Codewhale session contains no journal entries or messages\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"pet/src/core/codewhale.ts","lineNumber":157,"sourceCode":"  const times = entries.map(e => parseTime(e.created_at)).filter((n): n is number => n !== undefined);\n  if (times.length < 2) return false;\n  const span = Math.max(...times) - Math.min(...times);\n  const envelope = created !== undefined && updated !== undefined ? updated - created : 0;\n  return envelope >= ENVELOPE_MIN_MS && span < COLLAPSED_SPAN_MS;\n}\n\nfunction pushEvent(events: WhaleEvent[], event: WhaleEvent): void {\n  events.push(event);\n}\n\nexport function fromCodewhaleSession(document: unknown, filename = 'Codewhale session', maxEvents = 250_000): Trace {\n  const root = obj(document);\n  const metadata = obj(root.metadata);\n  const sessionId = str(metadata.id) ?? filename;\n  const journal = obj(root.journal);\n  const { entries, warnings } = activeJournalEntries(journal);\n  const sourceEntries: Obj[] = entries.length ? entries : (Array.isArray(root.messages) ? root.messages.map((message: unknown, i: number) => ({ id: `${sessionId}/message/${i}`, kind: 'message', message })) : []);\n  if (!sourceEntries.length) throw new Error('Codewhale session contains no journal entries or messages.');\n  const created = parseTime(metadata.created_at);\n  const updated = parseTime(metadata.updated_at);\n  const orderOnly = collapsedTimestamps(sourceEntries, created, updated);\n  if (orderOnly) {\n    warnings.push('Journal created_at values are collapsed to last-save time, not execution time. The time axis is journal order (1 ms per emitted event), not wall-clock duration. Gap, burst, and cycle-period findings are not execution-time claims.');\n  } else {\n    const times = sourceEntries.map(e => parseTime(e.created_at)).filter((n): n is number => n !== undefined);\n    if (!times.length) warnings.push('Journal entries have no usable timestamps. The time axis is journal order.');\n  }\n\n  const events: WhaleEvent[] = [];\n  const pending = new Map<string, number>();\n  let seq = 0;\n  const originWall = orderOnly ? undefined : sourceEntries.map(e => parseTime(e.created_at)).find((n): n is number => n !== undefined);\n  const agentId = 'parent';\n  const model = str(metadata.model);\n  const provider = str(metadata.model_provider);\n","sourceCodeStart":139,"sourceCodeEnd":175,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/433685b2024e7bc4c99e1e2e326bcad39b4d9d65/pet/src/core/codewhale.ts#L139-L175","documentation":"fromCodewhaleSession() converts a Codewhale session document (journal plus optional top-level messages) into a trace. It throws when the active journal yields no entries and the document also has no messages array, because a session with no inspectable content cannot produce any events. This is a fail-fast guard before the expensive entry-to-event conversion.","triggerScenarios":"Importing a session JSON where root.journal has no active entries (all filtered out by activeJournalEntries) and root.messages is absent or an empty array — e.g. a brand-new session, a session whose entries were all pruned, or reading the wrong file.","commonSituations":"Exporting a session immediately after creation before any turn ran, exporting after a session reset/cleanup, or pointing the importer at a metadata-only stub file.","solutions":["Inspect the session JSON: confirm root.journal has entries (not all filtered as inactive) or root.messages is a non-empty array.","Re-export the session after at least one completed turn so journal entries exist.","If a session may legitimately be empty, guard the call site and skip instead of importing."],"exampleFix":"// before\nconst trace = fromCodewhaleSession(doc, file);\n// after\nif (!doc?.journal?.entries?.length && !doc?.messages?.length) { console.warn(`skipping ${file}: empty session`); return; }\nconst trace = fromCodewhaleSession(doc, file);","handlingStrategy":"validation","validationCode":"const entries = doc?.journal?.entries ?? [];\nconst messages = Array.isArray(doc?.messages) ? doc.messages : [];\nif (entries.length === 0 && messages.length === 0) { skip(file); return; }\nconst trace = fromCodewhaleSession(doc, file);","typeGuard":"const hasSessionContent = (d: any): boolean => !!d && ((d.journal?.entries?.length ?? 0) > 0 || (Array.isArray(d.messages) && d.messages.length > 0));","tryCatchPattern":"try { trace = fromCodewhaleSession(doc, file); }\ncatch (e) { if (e.message.includes('no journal entries or messages')) return null; throw e; }","preventionTips":["Skip zero-byte or metadata-only session files before import.","Only export sessions after at least one completed turn.","Batch imports with per-file try/catch so one empty session doesn't abort the run."],"tags":["import","empty-input","session"],"backgroundTag":"empty-result-set","analyzedSha":"433685b2024e7bc4c99e1e2e326bcad39b4d9d65","analyzedAt":"2026-09-15T12:24:24.634Z","contentChangedAt":"2026-09-15T12:24:24.634Z","schemaVersion":2},"datasetVersion":"2026-09-22T11:17:16.035Z"}