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

When loading a Codewhale session for the pet view, the loader reads root.journal entries, falling back to root.messages. If neither yields any entries, it throws 'Codewhale session contains no journal entries or messages.' because there is nothing to render on the pet timeline.

Solutions

  1. Verify the session file actually contains journal.entries or messages and pick a non-empty session
  2. Inspect why activeJournalEntries filtered everything out (deleted/pruned entries) and relax or fix the filter
  3. Check the file format/version — if entries live under another key, update the loader or convert the file
  4. Regenerate or re-export the session from the source app

Example fix

// before
loadSession('session-empty.json');
// after
const data = JSON.parse(fs.readFileSync('session-empty.json', 'utf8'));
const hasEntries = data.journal && Object.keys(data.journal).length > 0;
const hasMessages = Array.isArray(data.messages) && data.messages.length > 0;
if (hasEntries || hasMessages) loadSession('session-empty.json');
else console.warn('session has no content, skipping');
Defensive patterns

Strategy: try-catch

Validate before calling

function sessionHasContent(root) {
  const journalEntries = root?.journal ? Object.keys(root.journal).length : 0;
  const messages = Array.isArray(root?.messages) ? root.messages.length : 0;
  return journalEntries > 0 || messages > 0;
}

Try / catch

try {
  loadSession(file);
} catch (err) {
  if (err.message.includes('no journal entries or messages')) {
    console.warn(`skipping empty session ${file}`);
  } else throw err;
}

Prevention

When it happens

Trigger: Opening a session file whose JSON has no journal object with active entries and no messages array — e.g. an empty/new session, a truncated or corrupted file, or a file from an incompatible format where entries exist under a different key.

Common situations: Pointing the importer at the wrong file (a metadata-only stub), a session wiped by a crash before the first write, schema drift where journal entries are nested differently, or all journal entries filtered out by activeJournalEntries (e.g. all marked deleted).

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/c981ff40147f6ecf. Report an issue: GitHub.

Appendix: source

Thrown at pet/ios/Resources/pet-native.js:2038

    const times = entries.map(e => parseTime(e.created_at)).filter((n) => 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, event) {
    events.push(event);
}
function fromCodewhaleSession(document, filename = 'Codewhale session', maxEvents = 250_000) {
    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 = entries.length ? entries : (Array.isArray(root.messages) ? root.messages.map((message, i) => ({ 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 !== undefined);
        if (!times.length)
            warnings.push('Journal entries have no usable timestamps. The time axis is journal order.');
    }
    const events = [];
    const pending = new Map();
    let seq = 0;
    const originWall = orderOnly ? undefined : sourceEntries.map(e => parseTime(e.created_at)).find((n) => n !== undefined);
    const agentId = 'parent';
    const model = str(metadata.model);
    const provider = str(metadata.model_provider);

View on GitHub (pinned to 433685b202)