[BUG] IDE extension (2.1.220) hangs the extension host in an infinite Intl.DateTimeFormat loop — prompt spins forever, never renders, RSS climbs to multi-GB
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
Using Claude Code as the IDE extension in Cursor (Remote-WSL), a submitted prompt
sometimes never returns. The status spinner cycles its words ("mulling… thinking…
transmuting…") indefinitely — 10+ minutes — and no output is ever rendered.
While it hangs, the extension-host node process pegs a full CPU core (~90–100%)
and its RSS climbs unbounded (observed 3 GB → 7 GB before I killed it). The VS Code/
Cursor window's other extensions stall too, and the process is so busy that even
V8's own inspector (--inspect) becomes unresponsive. The only recovery is to
SIGKILL the extension host and reload the window.
I captured native stacks of the pegged V8 main thread with gdb (the inspector can't
attach — the loop never yields). Two independent samples both land in the same call
chain: the extension is constructing Intl.DateTimeFormat in a hot loop, and each
construction rebuilds ICU's timezone/calendar/date-pattern-generator, which is
extremely expensive. Across a growing conversation this becomes O(messages × tokens)
of ICU work on the event loop, which is what blocks rendering.
This is not environment-specific — it's the extension repeatedly building Intl
formatters (timestamp formatting) instead of caching a formatter instance.
What Should Happen?
The prompt completes and the response renders; the extension host stays responsive
and its memory does not grow unbounded. Timestamp formatting should reuse a cached
Intl.DateTimeFormat instance rather than constructing a new one per render/token.
Error Messages/Logs
No error is thrown — it silently hangs (part of the problem). Native stack of the
pegged V8 main thread (gdb `thread apply all bt`, extension-host node v22.23.1),
two samples ~0.5s apart:
# Sample 1
#2 icu_78::OlsonTimeZone::clone() const
#4 icu_78::GregorianCalendar::clone() const
#5 v8::internal::JSDateTimeFormat::CreateDateTimeFormat(...)
#6 v8::internal::JSDateTimeFormat::New(...)
#7 v8::internal::Builtin_DateTimeFormatConstructor(int, unsigned long*, Isolate*)
#8+ ?? () <- extension's JIT'd JS (unsymbolized)
# Sample 2
#3 icu_78::DateTimePatternGenerator::copyHashtable(...)
#4 icu_78::DateTimePatternGenerator::clone() const
#5 v8::internal::(anonymous)::DateTimePatternGeneratorCache::CreateGenerator(...)
#6 v8::internal::JSDateTimeFormat::CreateDateTimeFormat(...)
#7 v8::internal::JSDateTimeFormat::New(...)
#8 v8::internal::Builtin_DateTimeFormatConstructor(...)
#9+ ?? ()
Both samples of a 100%-CPU thread bottoming out in Builtin_DateTimeFormatConstructor
→ ICU clone = `new Intl.DateTimeFormat(...)` being called in a tight loop.
Steps to Reproduce
Not deterministically triggerable on demand, but reproducible in the sense that it
recurs and correlates with conversation length:
- Use the Claude Code IDE extension inside Cursor (VS Code-based) over Remote-WSL.
- Have an ongoing conversation in the panel (streamed responses; longer transcript
= higher chance).
- Submit another prompt (even a short one).
- Intermittently, the spinner cycles forever and no output renders; the ext-host
node process pegs a core and RSS grows.
To confirm the cause on a live hang (since --inspect is starved):
sudo sysctl -w kernel.yama.ptrace_scope=0
gdb -p <extension-host-pid> -batch -ex "set pagination off" -ex "thread apply all bt 30"
# find the ext-host pid: pgrep -f type=extensionHost (the one with a native-binary/claude child)
The busy thread bottoms out in Builtin_DateTimeFormatConstructor every time.
Claude Model
_No response_
Is this a regression?
I don't know
Last Working Version
_No response_
Claude Code Version
2.1.220 (Claude Code) [IDE extension: anthropic.claude-code-2.1.220]
Platform
Anthropic API
Operating System
Windows
Terminal/Shell
WSL (Windows Subsystem for Linux)
Additional Information
Root cause and suggested fix: the extension appears to construct Intl.DateTimeFormat
(or Intl.NumberFormat / toLocaleTimeString) per render/token when formatting message
timestamps. Each construction rebuilds ICU's OlsonTimeZone, GregorianCalendar, and
DateTimePatternGenerator (the stacks show it mid-clone()/copyHashtable), which is
very costly. Build the formatter ONCE and reuse it (module-level cached instance),
and avoid reformatting the whole transcript on every stream tick.
Note: because the loop never yields, the V8 inspector is unresponsive during the
hang — native stack sampling (gdb/perf) is required to observe it, not --inspect.