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

  1. Fix the hook to throw Error instances and handle its own exceptions
  2. Identify the offending hook from the stringified value after the prefix
  3. Disable the hook/extension and retry the tool call
  4. 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

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


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/141a3b8c53a0e4ab. Report an issue: GitHub.