Resume crashes with "g9H is not a function" — REPL onSessionRestored undefined in 2.1.120

Status Fixed / completed
Reported on v2.1.108
Maintainer reply ✓ Yes — wolffiex
Activity 14 comments · opened Apr 24, 2026 · closed Apr 25, 2026
💡 Likely answer: A maintainer (wolffiex, collaborator) responded on this thread — see the highlighted reply below.

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's enabled: false branch should return a no-op onSessionRestored, 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.

View original on GitHub ↗

14 Comments

lucasygu · 4 months ago

Confirming the regression range and that this is REPL-internal rather than terminal-emulator-specific:

  • 2.1.119 is the last known good version. Pinning the symlink to ~/.local/share/claude/versions/2.1.119 resolves 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).
  • Reproduces identically in cmux (a separate macOS terminal emulator that embeds libghostty independently of Claude Code). Same g9H is not a function minified name, same stack at cli.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 also rm the offending binary on disk. claude -p print 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's enabled: false no-op return so the producer/consumer contract matches:

function FXK(H) {
  return {
    onBeforeQuery: async () => true,
    onTurnComplete: async () => {},
    onSessionRestored: () => {},   // missing in 2.1.120
    render: () => null,
    ownsInput: false,              // missing in 2.1.120
  };
}

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.

huangyingw · 4 months ago

Confirming on Linux (Ubuntu) with claude 2.1.120 installed at ~/.local/share/claude/versions/2.1.120 — same crash. Symptoms identical to OP, only the minified name differs (g78 in my build vs g9H in OP's, expected from build-to-build minifier output).

ERROR  g78 is not a function. (In 'g78(z)', 'g78' is undefined)
 /$bunfs/root/src/entrypoints/cli.js:9247:5663

Same diagnosis: Cf9({enabled: S=false, ...}) (= FXK({enabled, ...}) in OP's labels) returns object without onSessionRestored; 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):

  1. ~/.claude/settings.json: add "maxVersion": "2.1.119" so auto-updater stops climbing past 119
  2. Physically delete ~/.local/share/claude/versions/2.1.120 so even if auto-updater tries to re-pin, the target is gone
  3. ln -sfn ~/.local/share/claude/versions/2.1.119 ~/.local/bin/claude

Just doing #3 alone gets reverted within minutes (confirmed independently — saw symlink mtime change without my touching it). #1 + #2 + #3 holds.

Adding platform:linux to the label set seems warranted.

Abhishek-Bhatta · 4 months ago

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:28Z by 2.1.119; CC auto-updated to 2.1.120 within ~6 minutes; first interactive resume attempt crashed with:

g9H is not a function. (In 'g9H(K)', 'g9H' is undefined)

The session data itself is not the issue.

Note on the maxVersion workaround 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:

  1. Session-resume smoke test with pre-populated data? The crash only fires when initialMessages.length > 0 — i.e. resuming any non-empty session. A single automated test that writes a session, bumps to a new build, and does claude --resume <id> interactively would have caught this immediately. Does that test exist? If not, it seems worth adding to the release gate.
  1. Internal dogfooding on nightly/canary? If engineers are using Claude Code daily on sessions that carry over from the previous day, this would have broken everyone's morning on the first internal build that shipped the regression, well before it hit the public release. How does Anthropic operate internally in terms of dogfooding?

Curious if the bug slipped through despite these measures. I would love to learn more.

tsukasaI · 4 months ago

+1 on macOS, claude 2.1.120, same minified symbol g9H and identical stack at cli.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-empty initialMessages hits the missing onSessionRestored regardless of which flag populated them.

Workaround that works for me without fighting the auto-updater:

claude # launch fresh, then use /resume interactively

The interactive /resume picker doesn't go through the crashing mount path.

edwrdcrpio · 4 months ago

Also hitting this on 2.1.120, macOS 24.6.0 (Darwin), arm64, native install at ~/.local/share/claude/versions/2.1.120. Confirmed claude -r <id> and claude -c both crash on REPL mount; claude + interactive /resume works on the same session files. Rolling back to 2.1.119 via symlink restores normal resume behavior.

Abhishek-Bhatta · 4 months ago

Can confirm that /resume picker works fine. Looks like we need a good ole Fri afternoon rollback.

wolffiex collaborator · 4 months ago

Sorry about this!!! Please roll back to 2.1.119. We are moving our pointer back.

MNitson · 4 months ago

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:

  1. Start a new session: claude
  2. Type /resume inside the session
  3. Pick the session you want to continue

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.

jiakuan · 4 months ago

Confirming on macOS (Darwin 24.6.0, Apple Silicon), Claude Code 2.1.120 installed via the native installer at ~/.local/share/claude/versions/. Every claude --resume <id> crashes with g9H is not a function at the same call site.

Workaround that worked cleanly for me: re-point the launcher symlink at the previous version that's still on disk —

ln -sfn ~/.local/share/claude/versions/2.1.119 ~/.local/bin/claude

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.

wolffiex collaborator · 4 months ago

Autoupdater should have done its thing by now. Please let us know if you are still having problems

Abhishek-Bhatta · 4 months ago

@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

marmutapp · 4 months ago

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:

~/.local/share/claude/versions$ ls
2.1.116  2.1.117  2.1.118  2.1.119  2.1.120
~/.local/share/claude/versions$ rm 2.1.120
~/.local/share/claude/versions$ ln -sf ~/.local/share/claude/versions/2.1.119 ~/.local/bin/claude

then claude --resume <session-id> works

josortmel · 4 months ago

Confirming on Windows 11 native, npm install (not the native installer or WSL):

  • Install: npm install -g @anthropic-ai/claude-code@2.1.120 (Bun-compiled claude.exe, not the ~/.local/share/claude/versions/ layout)
  • Bundle minifies the symbol as FKH (vs g9H, g78, UKH reported by others) ? confirms the bug is upstream of minification, not build-variant specific
  • Trigger: claude --resume <id> and --continue both crash on TUI mount with FKH is not a function. (In 'FKH(K)', 'FKH' is undefined) at cli.js:9273:5663

The 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.latest was still pointing at 2.1.119 ? the updater appears to grab the highest published version regardless of the latest tag.

Same fix worked: npm install -g @anthropic-ai/claude-code@2.1.119. Pinning with DISABLE_AUTOUPDATER=1 prevents re-pull while waiting for >2.1.120 release with the fix.

github-actions[bot] · 4 months ago

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.