PreToolUse hook systemMessage never renders (rendered:false) — invisible in plan-approval dialog

Status Open
Reported on v2.1.278
Maintainer reply None cached
Activity 0 comments · opened Sep 21, 2026

Summary

A PreToolUse hook's systemMessage is recorded in the session transcript as a
hook_system_message attachment carrying rendered: false, and never displays anywhere in the
UI — not in the tool's permission/approval dialog, not in the transcript view. In the same
session, additionalContext attachments (hook_additional_context) rendered 16/16. This makes
systemMessage a dead channel for exactly the case it exists for: putting a security-relevant
warning in front of the human at decision time.

Environment

  • Claude Code 2.1.278, macOS (Darwin 25.6.0), interactive terminal session

Reproduction

  1. Register a PreToolUse hook on matcher ExitPlanMode that returns a deny-capable JSON

decision with BOTH channels populated, e.g.:

``json
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "ask",
"permissionDecisionReason": "This plan describes an operator-reserved action…",
"systemMessage": "This plan describes an operator-reserved action and needs your explicit authorization before it proceeds: privilege escalation (sudo); destructive filesystem operation (rm -rf). Review before approving."
}
}
``

  1. In a session governed by that registration, have Claude write a plan (plan mode) that

contains the flagged content and call ExitPlanMode.

  1. Observe the plan-approval dialog.

Expected

The permissionDecisionReason and/or systemMessage text is visible to the human somewhere at
approval time — ideally inside or adjacent to the plan-approval dialog, since ask exists to
put a reason in front of the user before they approve.

Actual

  • The approval dialog is the completely generic plan view ("Claude has written up a plan and is

ready to execute. Would you like to proceed?" + the three standard options). No hook text
anywhere. Verified by a human watching the dialog and copying it verbatim during the exact
round trip where the hook fired.

  • The hook demonstrably fired and emitted: the session .jsonl transcript contains the

hook_system_message attachment with the exact warning text, bound to the ExitPlanMode
tool call's toolUseID, with rendered: false.

  • Across the session: hook_system_message attachments 0/4 rendered; hook_additional_context

attachments 16/16 rendered. So this is specific to the systemMessage attachment type, not a
general attachment-display problem.

Impact

Any PreToolUse gate that uses ask + systemMessage to surface a warning at approval time is
mechanically live but humanly silent — the permission prompt appears, but the reason it appeared
never reaches the person approving. For security-shaped hooks (flagging privileged/destructive
actions inside plans before approval) this defeats the purpose of the ask decision: the user
sees a normal approval dialog with no indication anything was flagged.

View original on GitHub ↗