Skip to content

Session resume freezes with 100% CPU due to redundant progress events in session files #22149

Closed as not planned

Description

@asem89

Describe the bug

Claude Code freezes with 100% CPU when attempting to resume conversations. The UI becomes unresponsive and the process must be killed.

Root Cause Analysis

Investigation revealed that session .jsonl files grow to hundreds of megabytes due to progress events storing the entire conversation history in normalizedMessages on every event.

Evidence from a 193MB session file:

  • 500 lines total
  • 426 progress events = 191.6 MB (99.9% of file)
  • Actual conversation (user/assistant/system) = 0.16 MB
  • Each progress event contains full normalizedMessages array (2264 messages in longest case)
  • Individual lines up to 1.4 MB each

The duplication pattern:

Early events:   progress with ~140 messages  → 0.72 MB
Middle events:  progress with ~500 messages  → 0.85 MB  
Late events:    progress with ~2264 messages → 1.44 MB

Every progress event duplicates the entire conversation history up to that point.

Impact

  • Session files grow to 100MB-400MB for long conversations
  • Resume picker must parse all these files → 100% CPU freeze
  • Storage waste: 99.9% of session files is redundant data

Expected behavior

progress events should either:

  1. Not include normalizedMessages (it's redundant - the conversation is already stored in user/assistant events)
  2. Store only a delta/reference
  3. Be excluded from session files entirely (they're only needed for live streaming UI)

Workaround

Strip progress events from session files:

import json

def clean_session(filepath):
    with open(filepath) as f:
        lines = [l for l in f if json.loads(l).get('type') != 'progress']
    with open(filepath, 'w') as f:
        f.writelines(lines)

Environment

  • Claude Code version: 2.1.27
  • OS: Linux

Activity

  1. github-actions commented on Jan 31, 2026

    @github-actions

    Found 3 possible duplicate issues:

    1. [BUG] Session files grow to multi-GB due to normalizedMessages duplication in subagent progress entries #19040
    2. CLI hangs at 99% CPU on startup with large session .jsonl files #22041
    3. [BUG] bash_progress events not compacted, causing multi-MB transcripts and resume hang #19199

    This issue will be automatically closed as a duplicate in 3 days.

    • If your issue is a duplicate, please close it and 👍 the existing issue instead
    • To prevent auto-closure, add a comment or 👎 this comment

    🤖 Generated with Claude Code

  2. asem89 commented on Jan 31, 2026

    @asem89
    Author

    Additional Finding: saved_hook_context duplication

    While investigating, I found a second source of session bloat:

    The Bug

    saved_hook_context entries (for SessionStart hooks) are written once per historical message instead of once per session.

    Evidence

    A session with 619 messages that was resumed ~9 times had:

    • 5350 saved_hook_context entries (should be ~9)
    • All entries had the same timestamp (written simultaneously on resume)
    • Each entry had a different parentUuid (one per message)
    • Only 1 unique toolUseID (confirming single hook execution)

    Pattern

    Session with N messages resumed K times:
    Expected saved_hook_context entries: K
    Actual saved_hook_context entries: N × K (quadratic!)
    

    Space Impact

    • 619 messages × 4.6KB per entry × 9 resumes = 24.8 MB wasted
    • This stacks with the progress event bloat

    Expected Behavior

    SessionStart hook context should be saved once per session start, not once per message in history.

  3. asem89 commented on Jan 31, 2026

    @asem89
    Author

    Third Finding: Duplicate subagent transcripts in task results

    The Bug

    When a Task tool completes, the subagent's full conversation transcript is stored twice in the parent session - once in toolUseResult.task.output and again in toolUseResult.task.result.

    Evidence

    Task result structure:
      output: 768.1 KB  ← full subagent transcript
      result: 768.1 KB  ← IDENTICAL copy
    
    Confirmed: output === result (same data stored twice)
    

    In one session with 16 subagent calls:

    • Total embedded transcript size: 21.4 MB
    • ~10.7 MB is duplicate data

    Expected Behavior

    Either:

    1. Store the transcript once (remove result or output)
    2. Or have result contain only a summary/reference, not the full transcript

    Combined Impact

    All three issues compound in long sessions with subagents:

    1. progress events duplicate full history (exponential)
    2. saved_hook_context duplicates per message (quadratic)
    3. task.output/task.result duplicate transcripts (2x per subagent)

    A session that should be ~2MB can easily grow to 200MB+.

  4. asem89 commented on Jan 31, 2026

    @asem89
    Author

    Comprehensive Audit Results (GPT-5.2 Analysis)

    A deep audit of ~/.claude/projects (~488 MB, 1,476 JSONL files) revealed 5 additional storage bugs beyond the original 3.

    Storage Breakdown

    • By event type: user 79.4%, assistant 18.2%, other ~2.4%
    • By field: toolUseResult ~226 MB (largest), message ~155 MB

    Additional Bugs Found

    Bug 4: Tool results stored redundantly (JSONL + message)

    user events often contain BOTH:

    • toolUseResult.stdout
    • message.content[].tool_result.content

    Evidence: In 20k sampled events, output was duplicated in 96-97% of cases.

    Bug 5: Tool output triple-stored (JSONL + message + file)

    Tool output appears in:

    1. tool-results/toolu_*.txt (full file)
    2. toolUseResult.stdout (full inline)
    3. message.tool_result.content (often full)

    Evidence: 81.2% of tool-results/*.txt bytes were duplicated in JSONL.

    Bug 6: Full file contents stored inline

    toolUseResult stores:

    • originalFile: ~87 MB across 2,547 occurrences
    • file: ~41 MB across 5,383 occurrences

    These are full file snapshots, not diffs, even though the filesystem has the file.

    Bug 7: Subagent streaming rewrites full transcript each update (O(N²))

    For local_agent tasks with status: running:

    • Each update's task.output is the full transcript-so-far
    • Same "rewrite full history" pattern as Bug 1

    Evidence:

    • Aggregate overhead: 2.14x average
    • Worst case: 3.6x for a single task

    Bug 8: Bash progress duplicates output fields

    For bash_progress events (571 sampled):

    • Both output and fullOutput always exist
    • 509/571 are identical
    • When different, fullOutput is ~3.87x larger

    Recommended Fixes (by ROI)

    1. Store tool output once - reference by {toolUseId, sha256} elsewhere
    2. Remove message.tool_result duplication - pick one canonical location
    3. Stream deltas for subagent/bash updates, not full prefix
    4. Replace file snapshots with diffs - store {path, pre_hash, post_hash, diff}
    5. Deduplicate subagent transcripts - don't store in both subagents/*.jsonl AND task.output/result
    6. Content-address saved_hook_context - store once globally, reference by hash

    Summary Table

    Bug Source Waste
    1. progress normalizedMessages Exponential history duplication 99% of affected files
    2. saved_hook_context per-message Quadratic on resume 24MB+ per session
    3. task.output === task.result Duplicate field 50% of subagent data
    4. toolUseResult vs message.tool_result Dual storage 96% duplicated
    5. tool-results/*.txt + inline Triple storage 81% duplicated
    6. originalFile/file full snapshots No diffing 128MB in corpus
    7. Subagent streaming full rewrite O(N²) growth 2-3.6x overhead
    8. output vs fullOutput Redundant fields 3.87x when different
  5. nikhilgikiai commented on Jan 31, 2026

    @nikhilgikiai

    claude code has become unusable and its got nothing to do with my CLAUDE.md or .claude folders
    works correctly from home folder, and works correctly when .claude/projects/ is cleared, but do not see anything if you try /resume from inside claude code, or --continue or --resume from terminal. Also orphan claude processes stay in memory for new native install on mac. release channel is latest, not stable and version is 2.1.27

    Other issues i saw: Haiku being used for something denied tool calls, and malformed json in responses which at least for a few hours i have not been able to trace to anything in my repo.

  6. dicksontsai commented on Jan 31, 2026

    @dicksontsai
    Collaborator

    2.1.27 could be related to #22042 rather than progress events. Progress events were fixed last week according to Claude Code oncall records.

  7. junaidtitan commented on Feb 10, 2026

    @junaidtitan

    Same problem here — progress events storing the entire conversation history on every tick, making session files unusable. Your analysis nailed it: 426 progress events = 191.6MB out of 193MB total. 99.9% waste.

    Built Cozempic specifically for this. The progress-collapse strategy detects consecutive progress tick messages and collapses them into a single entry. On a session like yours it would take that 193MB down to a few MB.

    pip install cozempic
    cozempic init

    cozempic init auto-wires a guard daemon that starts on every session and prunes this bloat continuously — so the file never gets large enough to cause the freeze in the first place. For an existing bloated session that's already stuck:

    cozempic treat <session_id> -rx aggressive --execute

    Then claude --resume should work again without the 100% CPU freeze.

    Would appreciate if you could try this on one of your affected sessions and let me know if it resolves the resume freeze. If there are progress patterns I'm not catching, I want to know so I can add them.

  8. github-actions commented on Mar 11, 2026

    @github-actions

    Closing for now — inactive for too long. Please open a new issue if this is still relevant.

  9. github-actions commented on Mar 19, 2026

    @github-actions

    This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.

  10. locked as resolved and limited conversation to collaborators on Mar 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions