[BUG] Claude Code 2.0.28 Freeze - JSON Serialization + StringTable + GC Thrashing (macOS)

Resolved 💬 4 comments Opened Oct 28, 2025 by kuzmeech Closed Nov 25, 2025

Claude Code 2.0.28 Freeze - JSON Serialization + StringTable + GC Thrashing (macOS)

Summary

Claude Code process enters infinite CPU burn (44% CPU) due to JSON serialization triggering StringTable lookups and continuous garbage collection. Process remains responsive to network but completely frozen for user interaction.

Environment

  • OS: macOS 26.0.1 (25A362)
  • Node: /opt/homebrew/Cellar/node/24.10.0/bin/node (v24.10.0)
  • Claude Code: 2.0.28
  • Platform: darwin (ARM64)
  • PID: 98962
  • Session Start: 2025-10-28 01:54 AM EDT
  • Duration at freeze: ~11 minutes
  • Memory: 1.0GB RSS (1079520 KB)
  • CPU: 44.4% constantly

Bug Description

Process enters infinite loop combining three operations:

  1. JSON Serialization (JsonStringify) - attempting to serialize large objects
  2. StringTable Lookups - string internalization for object keys
  3. Garbage Collection - continuous scavenging trying to free memory

Result: Process burns CPU indefinitely but makes no progress. Terminal appears frozen but process continues running in background.

Root Cause Analysis

CPU Sample Evidence (10 seconds, 8614 samples)

Hot Functions:

  • JsonStringify: 250 samples (2.9% of samples) - JSON serialization active
  • StringTable operations: 34 samples (0.4%) - string internalization
  • Garbage Collection: 66 samples (0.8%) - continuous GC activity

Call Stack Pattern:

RunMicrotasks →
  PromiseFulfillReactionJob →
    AsyncFunctionAwaitResolveClosure →
      [User JS Code] →
        JsonStringify (JSON.stringify()) →
          StringTable::TryStringToIndexOrLookupExisting →
            ObjectPrototypeHasOwnProperty →
              Garbage Collection triggered

Performance Anti-Pattern:

JSON.stringify(large_object)
  → Creates many temporary strings for keys/values
  → Triggers StringTable lookups for internalization
  → Allocates memory for serialized output
  → Triggers GC to free temporary strings
  → GC frees memory but stringify creates more
  → Infinite loop: serialize → allocate → GC → repeat

Steps to Reproduce

Note: Difficult to reproduce reliably - appears to happen during background operations.

  1. Start Claude Code 2.0.28 in any project
  2. Work normally for 10-15 minutes
  3. Session begins internal JSON serialization (likely saving state/session)
  4. Process enters freeze state - high CPU, no progress
  5. Terminal appears frozen but background process continues

Characteristics:

  • Not triggered by specific user action
  • Appears to be internal Claude Code operation
  • Process shows activity but no visible progress
  • No error messages or logs

Expected Behavior

  • JSON serialization should complete or timeout
  • GC should stabilize memory usage
  • Process should either succeed or fail with error
  • Terminal should remain responsive

Actual Behavior

  • Infinite CPU burn at ~44%
  • Process appears "alive" but frozen
  • No timeout or error recovery
  • Only solution: force kill process
  • Session/context lost

Impact

  • Severity: High - renders session unusable
  • Frequency: Occasional (background operation triggered)
  • Workaround: None - must kill process and restart
  • Data loss: Current session state lost
  • User impact: Work interruption, context loss

Technical Evidence

Process State

PID:     98962
CPU:     44.4% (constant)
Memory:  1.0GB RSS
Status:  Running (frozen)
Runtime: 11+ minutes

Sample Analysis (10s, 8614 samples)

Key Operations:
- JsonStringify:    250 samples (JSON serialization)
- StringTable:       34 samples (string internalization)
- GarbageCollect:    66 samples (memory management)
- hasOwnProperty:     9 samples (object property checks)

Pattern: JSON serialization loop with GC thrashing

Evidence Files

Gist: https://gist.github.com/kuzmeech/d388717c72287d66e9526dc75c501e7c

Files:

  • processes_info.txt - Summary of both processes
  • sample_98962_sanitized.txt - Full 10s CPU sample (305 lines)

Why This Is NOT a Duplicate

Analysis conducted: Reviewed similar V8/JSON/StringTable issues from past 4 months.

Issue #10349 - "100% CPU usage - V8 StringTable performance collapse"

  • Version: v2.0.27 (Oct 26, 2 days ago) - reported by same user
  • Root cause: StringTable lookups during dynamic object property creation
  • Stack: Array.mapSetKeyedPropertyStringTable::LookupString
  • Trigger: Building objects with many unique property names in loops
  • Pattern: Progressive degradation over 22 minutes, memory 3.2→5.0GB
  • This issue (v2.0.28): StringTable lookups during JSON serialization
  • Stack: JsonStringifyhasOwnPropertyStringTable::TryStringToIndexOrLookupExisting
  • Trigger: Serializing large objects to JSON
  • Pattern: Immediate high CPU, stable memory 1.0GB
  • Conclusion: Different triggers (object creation vs JSON serialization), different entry points

Issue #4580 - "Claude Code freezes with 100% CPU during multi-agent task JSON serialization"

  • Version: v1.0.61 (Jul 28, 3 months old)
  • Root cause: JSON serialization with 2000+ recursive calls
  • Stack: JsonStringifier::Serialize_ (deep recursion)
  • Trigger: Task tool trying to serialize sub-agent responses
  • Pattern: Recursive depth explosion
  • This issue (v2.0.28): JSON serialization with StringTable + GC thrashing
  • Stack: JsonStringifyStringTableGC (no deep recursion)
  • Trigger: Background session serialization
  • Pattern: Horizontal thrashing (not vertical recursion)
  • Conclusion: Same symptom (JSON freeze) but different mechanism (recursion vs thrashing)

Issue #10479 - "Claude Code 2.0.28 Freezes on Large API Responses - V8 JSON Parser + GC Thrashing"

  • Version: v2.0.28 (Oct 28, <1 day ago) - reported by same user
  • Root cause: JSON parsing (opposite direction)
  • Stack: JsonParseJsonParser::ParseJsonObject
  • Trigger: Reading large API response (45k tokens)
  • Pattern: Parse → allocate → GC → repeat
  • This issue (v2.0.28): JSON serialization (opposite direction)
  • Stack: JsonStringifyStringTableGC
  • Trigger: Serializing session state
  • Pattern: Stringify → allocate → GC → repeat
  • Conclusion: Opposite directions (parse vs stringify), both expose V8 limits

Summary Table

| Issue | Version | Age | Root Cause | V8 Operation | Trigger | Pattern | Status |
|-------|---------|-----|------------|--------------|---------|---------|--------|
| #4580 | v1.0.61 | 3mo | JSON recursion | JsonStringifier (serialize) | Task tool | Deep recursion | Different |
| #10349 | v2.0.27 | 2d | StringTable lookups | StringTable (property set) | Object creation | Progressive slow | Different trigger |
| #10479 | v2.0.28 | <1d | JSON parsing | JsonParser (parse) | API response | Parse + GC loop | Opposite direction |
| This | v2.0.28 | New | JSON + StringTable + GC | JsonStringify | Session serialize | Thrashing loop | Unique combo |

Common thread: Multiple V8 scalability issues in Claude Code's Node.js architecture.

Why this is unique:

  1. Combination issue: JSON serialization triggering StringTable lookups triggering GC
  2. Background operation: Not user-triggered, appears to be internal state saving
  3. Specific call path: JsonStringifyhasOwnPropertyStringTable (not seen in other issues)
  4. High CPU with stable memory: Unlike #10349 (growing memory) or #10479 (parsing)

Suggested Fixes

  1. Immediate:
  • Add timeout for JSON.stringify operations
  • Limit size of objects being serialized
  • Add progress indicators for background operations
  • Implement circuit breaker for runaway serialization
  1. Short-term:
  • Use streaming JSON serialization for large objects
  • Implement chunking/pagination for session state
  • Add telemetry to detect serialization loops
  • Optimize object structures to reduce serialization overhead
  1. Long-term:
  • Consider alternative serialization format (MessagePack, Protocol Buffers)
  • Redesign session persistence to avoid large serializations
  • Implement incremental state saving
  • Consider Golang rewrite (#9604) to avoid V8 limits

Related Issues

  • #10349 - 100% CPU, V8 StringTable collapse (v2.0.27, 2d old - different trigger: object creation)
  • #4580 - JSON serialization freeze (v1.0.61, 3mo old - different mechanism: deep recursion)
  • #10479 - JSON parsing freeze (v2.0.28, <1d old - opposite direction: parse vs stringify)
  • #9604 - Proposal: Golang rewrite (architectural solution to V8 limitations)

Additional Notes

  • This occurred in background - no user action triggered it
  • Process continued running (not crashed) but made no progress
  • Appears to be automatic session state serialization
  • Affects normal usage - happens during regular work
  • May correlate with session size/complexity

---

Evidence available in gist (sanitized, no personal info)

View original on GitHub ↗

This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗