can1357/oh-my-pi · warning · Error

${reason}

Error message

${reason}

What it means

During tool execution, extension call-handlers may veto the call by returning { block: true, reason }. When that happens, wrapper.execute throws an Error whose message is the handler's reason (defaulting to 'Tool execution was blocked by an extension'). The error originates from your own extension's blocking logic, not a core failure.

Source

Thrown at packages/coding-agent/src/extensibility/extensions/wrapper.ts:227

		let effectiveParams = params;
		if (!loopEmittedToolCall && this.runner.hasHandlers("tool_call")) {
			try {
				const callResult = (await this.runner.emitToolCall(
					{
						type: "tool_call",
						toolName: this.tool.name,
						toolCallId,
						input: normalizeToolEventInput(
							this.tool.name,
							resolveToolEventInput(this.tool, toolEventArgs(params, context)),
						),
					},
					signal,
				)) as ToolCallEventResult | undefined;

				if (callResult?.block) {
					const reason = callResult.reason || "Tool execution was blocked by an extension";
					throw new Error(reason);
				}
				// A non-blocking handler may replace the execution input. The returned object is the raw
				// input passed to `execute` (handler-owned; not re-normalized). Skipped for `computer`
				// tool calls, whose event input is a synthetic {actions,pendingSafetyChecks} view
				// (see toolEventArgs) rather than the real execution params.
				if (callResult?.input !== undefined && context?.toolCall?.providerMetadata?.type !== "computer") {
					effectiveParams = callResult.input as typeof params;
				}
			} catch (err) {
				if (err instanceof Error) {
					throw err;
				}
				throw new Error(`Extension failed, blocking execution: ${String(err)}`);
			}
		}

		// 2. Full approval gate against the (possibly revised) input that will actually run — resolves
		// policy and prompts on `effectiveParams`, so the user approves exactly what executes. A revised

View on GitHub (pinned to 9690622007)

Solutions

  1. Read the error message reason to identify which extension blocked the call and why.
  2. Adjust or disable the blocking extension's policy/config so the intended call is permitted.
  3. Run with extensions disabled or a reduced set to confirm which extension is the blocker, then fix its rules.
  4. If the block is intentional, handle it in your code as a controlled refusal instead of an unexpected failure.

Example fix

// before
await tool.execute(...); // throws 'Writes outside /tmp are not allowed'
// after
try {
  await tool.execute(...);
} catch (err) {
  if (err.message.includes('blocked by an extension') || isExtensionBlock(err)) {
    logger.warn('Tool call blocked by policy', { reason: err.message });
    return; // controlled refusal
  }
  throw err;
}
Defensive patterns

Strategy: try-catch

Validate before calling

const verdict = policyExtension.allows(toolName, params);
if (!verdict.allowed) {
  logger.warn('call would be blocked', { reason: verdict.reason });
  return;
}

Type guard

function isExtensionBlockError(err: unknown): err is Error & { blockedByExtension: true } {
  return err instanceof Error && (err.message.includes('blocked by an extension') || typeof (err as any).blockedByExtension === 'boolean');
}

Try / catch

try {
  result = await execute(...);
} catch (err) {
  if (isExtensionBlockError(err)) {
    logger.warn('tool call blocked by extension policy', { reason: err.message });
    return blockedResult(err.message);
  }
  throw err;
}

Prevention

When it happens

Trigger: An extension registered a tool-call handler that returns { block: true } for the given tool/params — e.g. a safety policy, allowlist, or audit rule matched this call.

Common situations: A security/policy extension blocks writes outside an allowed directory; a rate-limit extension blocks after N calls; a custom guard blocks 'rm' commands; the block fires in CI where config differs from local dev.

Related errors


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