# Atlas HookBlockError: a config hook blocked the tool call

> Read the hook's message, then find the tool.execute.before hook with blocking: true in your `hooks` config and relax its condition or drop `blocking`.

Atlas throws HookBlockError because a config-defined shell hook registered on tool.execute.before with blocking: true threw to deny the tool call, and the error text you are reading is whatever that hook printed, so the fix is to open the `hooks` block in your Atlas config, find the before-hook with blocking: true, and either relax its condition or drop `blocking` so the hook warns instead of denying. Atlas catches HookBlockError in session/tools.ts and tells the model the tool was denied, so no tool ran and nothing was written. Before you weaken the hook, consider that the common intended use is denying a dangerous command. If the block is correct, change the command instead of the hook.

## Symptom

A tool call fails with a HookBlockError whose message is whatever your before-hook printed, and the model is told the tool was denied.

## Cause

Config-defined shell hooks run on tool lifecycle events. A hook registered on tool.execute.before with blocking: true can throw HookBlockError to deny the tool, and session/tools.ts catches it.

## Fix

1. Read the hook's message. The error text you see is exactly what your before-hook printed, so it names the reason the block fired.
2. Inspect the `hooks` block in your Atlas config and find the hook registered on tool.execute.before with blocking: true.
3. Decide whether the block was correct. The common intended use is denying a dangerous command, in which case the hook is right and the command is wrong.
4. If the block is correct, change the command the agent tried to run rather than the hook that stopped it.
5. If the block is overreaching, relax the hook's condition so it only fires on the cases you actually want denied.
6. Or drop `blocking` from the hook so it warns instead of denying, and the tool call proceeds while the hook still reports.
7. Re-run the tool call and confirm it executes without raising HookBlockError.

## Why does Atlas throw HookBlockError on a tool call

Atlas throws HookBlockError when a config-defined shell hook registered on the tool.execute.before lifecycle event with blocking: true throws to deny the tool. session/tools.ts catches it and reports the denial to the model, so the tool never executed and 0 bytes were written to your files.

HookBlockError comes from your own configuration, not from Atlas policy. Config-defined shell hooks run on tool lifecycle events, and a hook attached to tool.execute.before sits directly in front of execution. When such a hook carries blocking: true, throwing HookBlockError is its supported way to veto the call. The message you see is not generated by Atlas: it is whatever your before-hook printed, which makes the error text the single most useful diagnostic on the page. Someone, possibly you, wrote that sentence into a hook because they wanted this exact class of tool call stopped. Read it before you touch anything.

## How to find the Atlas hook that blocked your tool call

Find the offending hook by opening the `hooks` block in your Atlas config and looking for a hook with 2 properties: registration on tool.execute.before, and blocking: true. Only a blocking before-hook can throw HookBlockError, so that pairing narrows the search to a handful of entries.

Two attributes identify the culprit precisely. The lifecycle event must be tool.execute.before, because a hook that runs after execution cannot prevent a tool from running. And blocking must be true, because a non-blocking hook has no authority to deny. Cross-reference the message text you saw in the HookBlockError against the shell command each candidate hook runs, and the match is usually obvious, since the hook printed that message itself. Atlas is extensible through plugins that contribute tools and hook into agent lifecycle events, so if the hook is not in your own config, check the plugins you have installed for one that registers a blocking before-hook.

## When the Atlas hook block is correct and the command is wrong

A HookBlockError in Atlas is often the correct decision. Denying a dangerous command is the common intended use of a blocking tool.execute.before hook, so before you relax it, check whether the hook caught exactly what it was written to catch. If the block is right, fix the command and change 0 hooks.

The instinct on hitting a block is to remove the block, and that instinct is wrong more often than not here. Hooks with blocking: true exist because a human decided a category of tool call should not proceed in this repository, and the agent just proposed one. Read the hook's message and ask a direct question: is the thing it stopped actually something you want to happen? If the answer is no, the system worked. Redirect the agent to a safer command and move on with the hook intact. Weakening a hook to get past a single turn removes the protection permanently, for every future session, in exchange for a few seconds now.

## How to relax an Atlas hook condition or make it non-blocking

Relax an over-broad Atlas hook in 1 of 2 ways: narrow the hook's condition so it fires only on the cases you genuinely want denied, or drop `blocking` from the hook definition so it warns instead of denying. Dropping blocking keeps the hook's reporting while letting the tool call proceed.

Narrowing the condition is the better of the two fixes when the hook has a legitimate purpose and is simply matching too much. Tighten the shell command's test so it targets the specific dangerous pattern rather than a broad class of tool calls, and the hook keeps its teeth where they matter. Dropping `blocking` is the right move when the hook was really meant as an observability or lint step and blocking: true was set by mistake, because a non-blocking hook still runs and still reports on the tool.execute.before event without throwing HookBlockError. Choose based on the hook's intent, not on which edit is faster.

## How to verify the Atlas hook fix worked

Verify by re-running the exact tool call that produced HookBlockError. A correct fix means Atlas executes the tool and session/tools.ts catches 0 blocks. Seeing the same hook message again means the hook still fires with blocking: true, so the condition you narrowed still matches your call.

The check is direct because the error text is your own. If the identical message comes back, your edit did not change the branch of the hook that was firing, so compare the hook's shell command against the specific tool call arguments it is seeing. If a different message comes back, a second blocking hook exists, and the same procedure applies to that one. If the tool runs cleanly, the fix landed. One thing worth remembering afterward: relaxing a hook is a durable change to your safety net, so if you loosened a condition to get one task done, revisit it and put the protection back where it belongs.

## FAQ

### what is HookBlockError in Atlas

HookBlockError is the error a config-defined Atlas hook throws to deny a tool call. A hook registered on tool.execute.before with blocking: true can throw it, and session/tools.ts catches it and tells the model the tool was denied.

### why did my Atlas tool call get denied by a hook

A shell hook in your Atlas config, registered on the tool.execute.before lifecycle event with blocking: true, threw HookBlockError. The error message you see is whatever that hook printed, so read it to learn why the block fired.

### how do I disable a blocking hook in Atlas

Open the `hooks` block in your Atlas config, find the hook on tool.execute.before with blocking: true, and drop `blocking` so it warns instead of denying. Consider narrowing the hook's condition instead, so the protection survives.

### where does the Atlas HookBlockError message text come from

The HookBlockError message is whatever your before-hook printed. Atlas does not generate it. That makes the message the fastest way to identify which hook in your `hooks` config fired and why.

### should I remove a hook that blocked a dangerous command

No. The common intended use of a blocking tool.execute.before hook is denying a dangerous command, so a block is often correct. If the hook caught what it was written to catch, change the command the agent tried to run rather than the hook.

### can an Atlas plugin block a tool call with a hook

Yes. Atlas is extensible through plugins that contribute tools and hook into agent lifecycle events, so a plugin can register a blocking tool.execute.before hook. If the offending hook is not in your own config, check your installed plugins.

### does a blocked tool call in Atlas still change files

No. A hook on tool.execute.before runs in front of execution, so when it throws HookBlockError the tool never runs. Nothing is written and nothing is changed, and the model is simply told the tool was denied.

---

Canonical HTML: https://runatlas.sh/resources/troubleshooting/hook-blocked-tool-call
Source of truth: aeo_pages row `/resources/troubleshooting/hook-blocked-tool-call` (segment: Troubleshooting) (this file is generated from it, never hand-edited).
Licence: Atlas is proprietary with a free core. It is not open source and there is no public source repository.
