Skip to content

Session permanently stuck after hook-based compaction: Cannot read properties of undefined (reading 'totalTokens') #30134

@uzihaq

Description

@uzihaq

Bug Description

After a hook-based compaction (fromHook: true), subsequent prompt attempts crash with:

TypeError: Cannot read properties of undefined (reading 'totalTokens')

The session becomes permanently bricked — every incoming message hits the same error. The only fix is manually archiving the session JSONL file.

Reproduction

This has occurred twice on the same session (same UUID f6ae2fc0-...), both times following the same pattern:

  1. Session accumulates ~180K tokens of context
  2. OpenClaw's hook-based compaction fires (visible as fromHook: true in the compaction entry)
  3. Compaction completes successfully (summary generated, firstKeptEntryId set)
  4. ~30 minutes of silence (no messages)
  5. Next incoming message immediately crashes with totalTokens TypeError
  6. Every subsequent attempt (including model fallback from opus → sonnet) hits the same crash
  7. Session is permanently stuck until the JSONL file is manually archived

Error Details

From gateway.err.log:

[diagnostic] lane task error: lane=main error="TypeError: Cannot read properties of undefined (reading 'totalTokens')"
[diagnostic] lane task error: lane=session:agent:main:main error="TypeError: Cannot read properties of undefined (reading 'totalTokens')"
Embedded agent failed before reply: Cannot read properties of undefined (reading 'totalTokens')

The error occurs during prompt preparation (before any LLM API call), not during compaction itself.

Session JSONL Analysis

The broken session shows this sequence after compaction:

Line 754: type=compaction  tokensBefore=182599  fromHook=true
Line 755: customType=openclaw.cache-ttl
Line 756: customType=openclaw:prompt-error  error="Cannot read properties of undefined (reading 'totalTokens')"
Line 757-777: Repeated prompt-error entries (8 total, alternating opus/sonnet attempts)

The kept messages (lines 711-753) include assistant messages with valid usage data — so the issue is not missing usage in the JSONL, but rather how the session state is reconstructed after hook-based compaction.

Likely Root Cause

The error traces to one of two locations:

  1. pi-coding-agent/dist/core/compaction/compaction.js:72calculateContextTokens(usage) does usage.totalTokens without a null check. The getAssistantUsage() / getLastAssistantUsageInfo() functions are supposed to guard against this, but after hook-based compaction the in-memory message array may not have proper usage data even though the JSONL does.

  2. src/auto-reply/reply/session.ts:418sessionStore[parentSessionKey].totalTokens could crash if the session store entry is in an inconsistent state after compaction, though this line has a guard check above it.

The key distinguishing factor is fromHook: true — this uses OpenClaw's extension-based compaction path rather than the internal pi-coding-agent compaction. The extension compaction may leave the in-memory session state inconsistent with what's persisted in the JSONL.

Suggested Fix

Add a null/undefined guard before accessing .totalTokens:

// In calculateContextTokens:
export function calculateContextTokens(usage) {
    if (!usage) return 0;  // Guard against undefined usage
    return usage.totalTokens || usage.input + usage.output + usage.cacheRead + usage.cacheWrite;
}

And/or ensure the hook-based compaction path properly reconstructs the in-memory message array with usage data intact.

Environment

  • OpenClaw version: latest (installed via npm)
  • OS: macOS (Darwin 25.2.0, arm64)
  • Model: claude-opus-4-6 (primary), claude-sonnet-4-6 (fallback)
  • Node: v25.6.1
  • Session type: persistent agent session (agent:main:main)

Workaround

Archive the broken session file to force a fresh session:

mv ~/.openclaw/agents/main/sessions/<session-id>.jsonl \
   ~/.openclaw/agents/main/sessions/<session-id>.jsonl.bak-$(date +%Y%m%d%H%M%S)

The next incoming message creates a new session automatically.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions