can1357/oh-my-pi · error · Error
Hook failed, blocking execution: ${String(err)}
Error message
Hook failed, blocking execution: ${String(err)} What it means
A hook handler itself threw a non-Error value while the tool was executing. Because hooks are fail-closed, any handler error blocks the tool call; non-Error throws are re-wrapped with this prefix (Error throws pass through unchanged).
Source
Thrown at packages/coding-agent/src/extensibility/hooks/tool-wrapper.ts:68
toolCallId,
input: normalizeToolEventInput(
this.tool.name,
resolveToolEventInput(this.tool, params as Record<string, unknown>),
),
})) as ToolCallEventResult | undefined;
if (callResult?.block) {
const reason = callResult.reason || "Tool execution was blocked by a hook";
throw new Error(reason);
}
// A non-blocking handler may replace the execution input. The returned object is the raw
// input the tool runs with (handler-owned); it is not re-normalized. Skipped for `computer`
// tool calls, whose real parameters are not represented by the event input.
if (callResult?.input !== undefined && context?.toolCall?.providerMetadata?.type !== "computer") {
effectiveParams = callResult.input as Static<TParameters>;
}
} catch (err) {
// Hook error or block - throw to mark as error
if (err instanceof Error) {
throw err;
}
throw new Error(`Hook failed, blocking execution: ${String(err)}`);
}
}
// Execute the actual tool, forwarding onUpdate for progress streaming
try {
const result = await this.tool.execute(toolCallId, effectiveParams, signal, onUpdate, context);
// Emit tool_result event - hooks can modify the result
if (this.hookRunner.hasHandlers("tool_result")) {
const resultResult = (await this.hookRunner.emit({
type: "tool_result",
toolName: this.tool.name,
toolCallId,
input: normalizeToolEventInput(View on GitHub (pinned to 9690622007)
Solutions
- Fix the hook to throw Error instances and handle its own exceptions
- Identify the offending hook from the stringified value after the prefix
- Disable the hook/extension and retry the tool call
- Wrap hook handler bodies in try/catch that convert failures to Error
Example fix
// before (in hook)
throw 'rule violation';
// after
throw new Error('rule violation'); Defensive patterns
Strategy: try-catch
Validate before calling
function hookIsSafe(fn) { try { fn({ name: 'probe' }); return true; } catch (e) { return e instanceof Error; } } Type guard
function isError(e: unknown): e is Error { return e instanceof Error; } Try / catch
try { await tool.execute(params); } catch (err) {
if (err instanceof Error && err.message.startsWith('Hook failed, blocking execution:')) {
logger.warn('hook crashed; disabled until fixed', { detail: err.message });
} else throw err;
} Prevention
- Wrap hook handler bodies in try/catch that convert failures to Error
- Never throw raw strings/objects from hooks
- Unit-test hooks against malformed inputs
- Fail hooks with block+reason instead of throwing when rejecting a call
When it happens
Trigger: A registered tool-call hook throws a raw string/object or rejects with a non-Error while wrapper.execute() runs the pre-call hook chain.
Common situations: Hook authors using throw 'msg' instead of new Error('msg'); hooks with bugs (null deref producing weird throw shapes, e.g. throw undefined); async hook rejecting with a plain value.
Related errors
- Extension failed, blocking execution: ${String(err)}
- Tool execution was blocked by a hook
- ${reason}
- Tool call denied by user: ${this.tool.name}
- Permission request cancelled
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/141a3b8c53a0e4ab.
Report an issue: GitHub.