[BUG] Claude Code 2.0.28 Freeze - JSON Serialization + StringTable + GC Thrashing (macOS)
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:
- JSON Serialization (
JsonStringify) - attempting to serialize large objects - StringTable Lookups - string internalization for object keys
- 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.
- Start Claude Code 2.0.28 in any project
- Work normally for 10-15 minutes
- Session begins internal JSON serialization (likely saving state/session)
- Process enters freeze state - high CPU, no progress
- 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 processessample_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.map→SetKeyedProperty→StringTable::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:
JsonStringify→hasOwnProperty→StringTable::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:
JsonStringify→StringTable→GC(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:
JsonParse→JsonParser::ParseJsonObject - Trigger: Reading large API response (45k tokens)
- Pattern: Parse → allocate → GC → repeat
- This issue (v2.0.28): JSON serialization (opposite direction)
- Stack:
JsonStringify→StringTable→GC - 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:
- Combination issue: JSON serialization triggering StringTable lookups triggering GC
- Background operation: Not user-triggered, appears to be internal state saving
- Specific call path:
JsonStringify→hasOwnProperty→StringTable(not seen in other issues) - High CPU with stable memory: Unlike #10349 (growing memory) or #10479 (parsing)
Suggested Fixes
- 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
- 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
- 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)
This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗