Resume crashes with "g9H is not a function" — REPL onSessionRestored undefined in 2.1.120
Summary
On 2.1.120, opening a prior session interactively via claude -r <session-id> (or --resume) crashes on mount with:
ERROR g9H is not a function. (In 'g9H(K)', 'g9H' is undefined)
/$bunfs/root/src/entrypoints/cli.js:9251:5663
Print mode (claude -p --resume <id> "…") works fine against the same session file, so the session data is healthy — the bug is purely in the interactive REPL mount path.
Environment
- Claude Code 2.1.120 (installed at
~/.local/share/claude/versions/2.1.120) - macOS (Darwin 25.3.0)
- Session was written progressively by 2.1.108 → 2.1.112 → 2.1.113; crash appears only after upgrading to 2.1.120
Repro
claude -r <any-session-id-with-messages>
# also:
claude --dangerously-skip-permissions -r <same-id>
Reproduces with and without --channels plugin flags, so plugins are not the trigger.
Diagnosis from the minified bundle
Inside the REPL component Ub8, which receives initialMessages as K:
let S = s_.useMemo(() => !1, []); // hardcoded false
let { onBeforeQuery: F9H,
onTurnComplete: ZLH,
onSessionRestored: g9H, // <- undefined
render: aM_,
ownsInput: LLH }
= FXK({ enabled: S, setMessages: F7, ... });
s_.useEffect(() => {
if (K && K.length > 0) {
HP_(K, K8()),
hY8({ abortController: new AbortController, taskRegistry: YH }),
tC8(K), UQ(K),
sYH.current.current = xz_(K, g8),
g9H(K); // <- TypeError here
}
}, []);
FXK({enabled: false, ...}) returns an object that does not include onSessionRestored; destructuring yields undefined; the mount effect invokes it unconditionally whenever the resumed session has any messages. Appears to fire on every interactive resume of a non-empty session.
Workaround
claude -p --resume <id> "…" works — print mode does not mount the REPL, so the broken effect never runs.
Suggested fix
Either:
FXK'senabled: falsebranch should return a no-oponSessionRestored, or- The mount effect should guard the call:
g9H?.(K).
Adjacent issue (lower priority)
If g9H is bypassed (e.g. by truncating the session so initialMessages is empty), a different mount effect fires and prints:
Error: sandbox required but unavailable: <reason>
+ sandbox.failIfUnavailable is set — refusing to start without a working sandbox.
sandbox.failIfUnavailable is not set in any of my settings files (user, user-local, project, project-local). It looks like --dangerously-skip-permissions implicitly sets isSandboxRequired() to true. That may be intentional defense-in-depth, but the error message blames a user setting that the user didn't set, which is misleading.
14 Comments
Confirming the regression range and that this is REPL-internal rather than terminal-emulator-specific:
~/.local/share/claude/versions/2.1.119resolves the crash; pinning to 2.1.120 reproduces it. The auto-updater eagerly re-points to 2.1.120 within minutes, so users wanting to stay on 2.1.119 also have to delete the 2.1.120 binary on disk — re-pointing the symlink alone gets reverted before the next launch (verified twice within ~10 minutes during a debugging session).g9H is not a functionminified name, same stack atcli.js:9251:5663, same--resume <sid>trigger. So this is purely in Claude Code's REPL mount path — not host-specific.Urgency note: this is a 100% reproducible startup crash on
claude --resume <sid>— every user trying to resume any non-empty session crashes immediately on 2.1.120. The auto-updater's re-application of 2.1.120 within minutes of a manual rollback makes the workaround fragile for users who aren't familiar enough with the install layout to alsormthe offending binary on disk.claude -pprint mode is unaffected (the REPL never mounts), so non-interactive scripted resume still works — the affected surface is the interactive REPL, i.e. the primary product surface.Recommended fix (matches the OP's diagnosis): add the two missing fields to
FXK'senabled: falseno-op return so the producer/consumer contract matches:The null-guard alternative (
g9H?.(K)) at the call site works too but is less robust — any future field added to the destructuring contract that the stub forgets will just resurface this bug. Filling out the stub is the safer pattern.Confirming on Linux (Ubuntu) with
claude 2.1.120installed at~/.local/share/claude/versions/2.1.120— same crash. Symptoms identical to OP, only the minified name differs (g78in my build vsg9Hin OP's, expected from build-to-build minifier output).Same diagnosis:
Cf9({enabled: S=false, ...})(=FXK({enabled, ...})in OP's labels) returns object withoutonSessionRestored; mount effect calls it unconditionally when initial messages exist.Workaround stack (sharing in case it helps others — also verifies @lucasygu's "auto-updater eagerly reverts symlink" observation):
~/.claude/settings.json: add"maxVersion": "2.1.119"so auto-updater stops climbing past 119~/.local/share/claude/versions/2.1.120so even if auto-updater tries to re-pin, the target is goneln -sfn ~/.local/share/claude/versions/2.1.119 ~/.local/bin/claudeJust doing #3 alone gets reverted within minutes (confirmed independently — saw symlink mtime change without my touching it). #1 + #2 + #3 holds.
Adding
platform:linuxto the label set seems warranted.Confirming on macOS (Darwin 24.6.0) with 2.1.120. I have a session (
5afb2353) that was written progressively by 2.1.118 → 2.1.119 and is otherwise healthy.Timeline: last entry in the session was written at
2026-04-25T00:34:28Zby 2.1.119; CC auto-updated to 2.1.120 within ~6 minutes; first interactive resume attempt crashed with:The session data itself is not the issue.
Note on the
maxVersionworkaround mentioned above:"maxVersion"is not a real settings field — the schema rejects it. To downgrade right now, physical deletion of the 2.1.120 binary is the only option, but the auto-updater reverts it quickly as others have noted. For future protection,"autoUpdatesChannel": "stable"(per docs: skips versions with major regressions) is the closest real knob — but it won't help you get off 2.1.120 today.---
A couple of questions for the Claude Code team:
initialMessages.length > 0— i.e. resuming any non-empty session. A single automated test that writes a session, bumps to a new build, and doesclaude --resume <id>interactively would have caught this immediately. Does that test exist? If not, it seems worth adding to the release gate.Curious if the bug slipped through despite these measures. I would love to learn more.
+1 on macOS, claude 2.1.120, same minified symbol
g9Hand identical stack atcli.js:9251:5663— same build artifact as OP.Triggered via
claude -c(continue last session), not--resume <sid>. Same crash, same call path, which confirms #53064 shares the same root cause: any REPL mount with non-emptyinitialMessageshits the missingonSessionRestoredregardless of which flag populated them.Workaround that works for me without fighting the auto-updater:
claude # launch fresh, then use /resume interactively
The interactive
/resumepicker doesn't go through the crashing mount path.Also hitting this on 2.1.120, macOS 24.6.0 (Darwin), arm64, native install at
~/.local/share/claude/versions/2.1.120. Confirmedclaude -r <id>andclaude -cboth crash on REPL mount;claude+ interactive/resumeworks on the same session files. Rolling back to 2.1.119 via symlink restores normal resume behavior.Can confirm that
/resumepicker works fine. Looks like we need a good ole Fri afternoon rollback.Sorry about this!!! Please roll back to 2.1.119. We are moving our pointer back.
Workaround: use /resume inside a running session
claude -r and claude -c crash on v2.1.120 (and 2.1.118/2.1.119) with the g9H is not a function error. However, the /resume command from within an already-running interactive session works reliably.
Steps:
This bypasses the crashing onSessionRestored code path that runs during CLI startup resume. Session data is unaffected - all JSONL files remain intact.
Tested on macOS (Apple Silicon), v2.1.118, 2.1.119, and 2.1.120. The CLI startup path (claude -r, claude -c, claude --resume) consistently crashes, while the
in-session /resume path works every time.
Confirming on macOS (Darwin 24.6.0, Apple Silicon), Claude Code 2.1.120 installed via the native installer at
~/.local/share/claude/versions/. Everyclaude --resume <id>crashes withg9H is not a functionat the same call site.Workaround that worked cleanly for me: re-point the launcher symlink at the previous version that's still on disk —
Sessions originally created under 2.1.120 resume without issue under 2.1.119, so this doesn't appear to be a transcript-format regression — purely a code path that's broken in the newer build. Posting in case it helps anyone else avoid losing access to in-flight sessions while the fix is in flight.
Autoupdater should have done its thing by now. Please let us know if you are still having problems
@wolffiex looks good! Would you or anyone else from CC team mind elaborating on the questions from earlier? Specifically https://github.com/anthropics/claude-code/issues/53041#issuecomment-4317283721
This also happens in the WSL version in Windows and the fix is the same. Removed 2.1.220 in
~/.local/share/claude/versions/and repoint the symlink to the last version you have in the same folder~/.local/share/claude/versions/which was 2.1.220:then
claude --resume <session-id>worksConfirming on Windows 11 native, npm install (not the native installer or WSL):
npm install -g @anthropic-ai/claude-code@2.1.120(Bun-compiledclaude.exe, not the~/.local/share/claude/versions/layout)FKH(vsg9H,g78,UKHreported by others) ? confirms the bug is upstream of minification, not build-variant specificclaude --resume <id>and--continueboth crash on TUI mount withFKH is not a function. (In 'FKH(K)', 'FKH' is undefined)atcli.js:9273:5663The npm distribution channel is also affected by the auto-update path: my machine pulled 2.1.120 on restart even though
npm view @anthropic-ai/claude-code dist-tags.latestwas still pointing at 2.1.119 ? the updater appears to grab the highest published version regardless of thelatesttag.Same fix worked:
npm install -g @anthropic-ai/claude-code@2.1.119. Pinning withDISABLE_AUTOUPDATER=1prevents re-pull while waiting for >2.1.120 release with the fix.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.