Hmbown/CodeWhale · error · Error

Codewhale session contains no journal entries or messages.

Error message

Codewhale session contains no journal entries or messages.

What it means

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.

Solutions

  1. Inspect the session JSON: confirm root.journal has entries (not all filtered as inactive) or root.messages is a non-empty array.
  2. Re-export the session after at least one completed turn so journal entries exist.
  3. If a session may legitimately be empty, guard the call site and skip instead of importing.

Example fix

// before
const trace = fromCodewhaleSession(doc, file);
// after
if (!doc?.journal?.entries?.length && !doc?.messages?.length) { console.warn(`skipping ${file}: empty session`); return; }
const trace = fromCodewhaleSession(doc, file);
Defensive patterns

Strategy: validation

Validate before calling

const entries = doc?.journal?.entries ?? [];
const messages = Array.isArray(doc?.messages) ? doc.messages : [];
if (entries.length === 0 && messages.length === 0) { skip(file); return; }
const trace = fromCodewhaleSession(doc, file);

Type guard

const hasSessionContent = (d: any): boolean => !!d && ((d.journal?.entries?.length ?? 0) > 0 || (Array.isArray(d.messages) && d.messages.length > 0));

Try / catch

try { trace = fromCodewhaleSession(doc, file); }
catch (e) { if (e.message.includes('no journal entries or messages')) return null; throw e; }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15). Data as JSON: /api/errors/3ea2cd66dd5a6825. Report an issue: GitHub.

Appendix: source

Thrown at pet/src/core/codewhale.ts:157

  const times = entries.map(e => parseTime(e.created_at)).filter((n): n is number => n !== undefined);
  if (times.length < 2) return false;
  const span = Math.max(...times) - Math.min(...times);
  const envelope = created !== undefined && updated !== undefined ? updated - created : 0;
  return envelope >= ENVELOPE_MIN_MS && span < COLLAPSED_SPAN_MS;
}

function pushEvent(events: WhaleEvent[], event: WhaleEvent): void {
  events.push(event);
}

export function fromCodewhaleSession(document: unknown, filename = 'Codewhale session', maxEvents = 250_000): Trace {
  const root = obj(document);
  const metadata = obj(root.metadata);
  const sessionId = str(metadata.id) ?? filename;
  const journal = obj(root.journal);
  const { entries, warnings } = activeJournalEntries(journal);
  const sourceEntries: Obj[] = entries.length ? entries : (Array.isArray(root.messages) ? root.messages.map((message: unknown, i: number) => ({ id: `${sessionId}/message/${i}`, kind: 'message', message })) : []);
  if (!sourceEntries.length) throw new Error('Codewhale session contains no journal entries or messages.');
  const created = parseTime(metadata.created_at);
  const updated = parseTime(metadata.updated_at);
  const orderOnly = collapsedTimestamps(sourceEntries, created, updated);
  if (orderOnly) {
    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.');
  } else {
    const times = sourceEntries.map(e => parseTime(e.created_at)).filter((n): n is number => n !== undefined);
    if (!times.length) warnings.push('Journal entries have no usable timestamps. The time axis is journal order.');
  }

  const events: WhaleEvent[] = [];
  const pending = new Map<string, number>();
  let seq = 0;
  const originWall = orderOnly ? undefined : sourceEntries.map(e => parseTime(e.created_at)).find((n): n is number => n !== undefined);
  const agentId = 'parent';
  const model = str(metadata.model);
  const provider = str(metadata.model_provider);

View on GitHub (pinned to 433685b202)