[BUG] SessionStart hook systemMessage silently dropped on --continue/--resume/fork when additionalContext matches one already in the transcript

Status Open
Reported on v2.1.281
Maintainer reply None cached
Activity 2 comments · opened Sep 24, 2026

Preflight

Searched existing issues. Related but different: #93458 (desktop app rewind, source=fork, a changed additionalContext never reaches the model). In the terminal CLI on 2.1.281 I see a narrower, deterministic mechanism: a changed additionalContext is injected fine on resume and fork; the drop happens only when the new additionalContext is identical to one already in the transcript, and it takes the user-facing systemMessage down with it.

What's Wrong?

On --continue, --resume <id> and --resume <id> --fork-session, a SessionStart hook's systemMessage is silently not displayed whenever the hook's additionalContext is byte-identical to a SessionStart additionalContext already present in the transcript.

  • Nothing is shown to the user (no SessionStart:resume says: ... line).
  • Neither hook_system_message nor hook_additional_context is written to the transcript for that launch.
  • The debug log still says Hook SessionStart (...) provided additionalContext (N chars), with no trace of the drop.

Skipping a duplicate additionalContext is reasonable (the model can still see the earlier identical copy in the history; I verified this with a marker that only ever appeared inside the attachment, and the model recalled it on the next resume). The problem is that the user-facing message of the same batch is discarded too.

The same drop happens when:

  • the additionalContext is unchanged but the systemMessage text is new (0/2 displayed);
  • the hook emits only a systemMessage (no additionalContext) and the transcript already holds any SessionStart additionalContext (0/2 displayed).

This is not a timing issue: with a random additionalContext on every launch, all 27 resume / continue / fork / compact launches displayed correctly, including hooks sleeping 0, 1, 3 and 8 seconds.

What Should Happen?

The hook's systemMessage is displayed on every launch. Deduplicating model-facing context against the transcript is fine, but display-only output should not be dropped with it.

Steps to Reproduce

  1. In an empty directory, create .claude/settings.json with a SessionStart hook that prints:

``json
{"systemMessage": "notice <random each run>", "hookSpecificOutput": {"hookEventName": "SessionStart", "additionalContext": "context <random each run>"}}
``

  1. Run claude, send one message, /exit. Run claude --continue a few times: the SessionStart:resume says: notice ... line is shown every time.
  2. Change the hook so additionalContext is a fixed string (keep the random systemMessage).
  3. claude --continue: the line is shown once (the fixed text is new to this transcript).
  4. claude --continue again, as often as you like: no SessionStart:resume says: line appears, and the transcript has no SessionStart attachment for those launches. In my runs this was 6/6 dropped across --continue, --resume <id>, --fork-session, after /compact (which resets the baseline once), and with tui: "fullscreen".
  5. Switch additionalContext back to random: every launch displays the line again.

Workaround: register a second SessionStart hook that emits a short, unique additionalContext (for example a timestamp). The batch then always has a new key and the first hook's systemMessage is kept (2/2), while its identical additionalContext is still deduplicated.

Likely cause

On resume, the SessionStart messages are deduplicated against the existing transcript, keyed on additionalContext and non-empty hook_success content. When no keyed item in the batch is new, the helper returns an empty list, which also discards the unkeyed hook_system_message entries of the same batch.

Suggested fix: deduplicate only the model-facing context and always keep display-only attachments (hook_system_message).

Claude Code Version

2.1.281 (native install)

Platform

Anthropic API (Claude subscription)

Operating System

macOS (Darwin 25.1.0)

Terminal/Shell

Terminal CLI inside tmux, zsh. Reproduced with the hook registered both through a plugin and through settings.json.

View original on GitHub ↗

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