[BUG] PreCompact hook exit code 2 does not block compaction

Resolved 💬 1 comment Opened Apr 4, 2026 by nullnull-kim Closed Apr 10, 2026

Preflight Checklist

  • [x] I've searched existing issues and didn't find a match
  • [x] I've read the documentation
  • [x] I can reproduce this issue consistently

What's Wrong?

PreCompact hook returning exit code 2 does not block compaction. The hook executes and displays the stderr message, but compaction proceeds regardless.

Source-level cause: executePreCompactHooks() return type only includes newCustomInstructions and userDisplayMessage — the blocked flag from executeHooksOutsideREPL (which does detect exit code 2) is not propagated to the caller in compact.ts.

The hook output shows:

Compacted PreCompact [...] failed: ⛔ compact 금지. /clear 후 새 세션으로 진행하세요.
✻ Conversation compacted (ctrl+o for history)

The "failed" message appears but compaction still completes.

What Should Happen?

PreCompact hooks should support the same exit code 2 blocking semantics as PreToolUse hooks. When a PreCompact hook returns exit code 2, compaction should be blocked and the stderr message should be displayed to the user.

Steps to Reproduce

  1. Create a PreCompact hook script:
// block-compact.js
process.stderr.write("⛔ compact blocked.");
process.exit(2);
  1. Register it in settings.json:
{
  "hooks": {
    "PreCompact": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "node /path/to/block-compact.js"
          }
        ]
      }
    ]
  }
}
  1. Run /compact in a Claude Code session.
  2. Expected: Compaction is blocked, message displayed.
  3. Actual: Message is displayed but compaction proceeds.

Use Case

  • Enforce /clear instead of compact to maintain explicit session boundaries
  • Prevent context loss from automatic compaction, letting users decide when to transition sessions

Claude Model

claude-opus-4-6

Is this a regression?

I don't know

Claude Code Version

2.1.88 (Claude Code)

Platform

Other

Operating System

Windows 11 Home 10.0.26200

Terminal/Shell

PowerShell

Additional Information

executeHooksOutsideREPL correctly sets blocked=true for exit code 2, but executePreCompactHooks() does not include blocked in its return type, so the blocking signal is lost before reaching the compact logic.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗