can1357/oh-my-pi · error · Error
Tool "${this.tool.name}" has pending provider safety checks
Error message
Tool "${this.tool.name}" has pending provider safety checks but no interactive UI is available. What it means
The tool call requires provider-side safety checks (e.g. server-enforced confirmation) but the current runner has no interactive UI, and provider safety checks cannot be bypassed by any setting or yolo mode — they fail closed. The wrapper throws this error instead of executing the tool.
Source
Thrown at packages/coding-agent/src/extensibility/extensions/wrapper.ts:311
const emitApprovalResolved = async (approved: boolean, reason?: string) => {
if (!hasApprovalHandlers) return;
await this.runner.emit({
type: "tool_approval_resolved",
sessionId,
toolName: this.tool.name,
toolCallId,
approved,
...(reason ? { reason } : {}),
});
};
// Provider safety checks fail closed without an interactive prompt. Unlike
// ordinary tier approval, no setting or yolo mode may bypass this gate.
if (!this.runner.hasUI()) {
const reason = "no interactive UI available";
await emitApprovalResolved(false, reason);
if (pendingSafetyChecks.length > 0) {
throw new Error(
`Tool "${this.tool.name}" has pending provider safety checks but no interactive UI is available.`,
);
}
throw new Error(
`Tool "${this.tool.name}" requires approval but no interactive UI available.\n` +
`Options:\n` +
` 1. Set tools.approvalMode: yolo in /settings\n` +
` 2. Add tools.approval.${this.tool.name}: allow to config\n` +
` 3. Use an interactive UI to approve the tool call`,
);
}
const uiContext = this.runner.getUIContext();
const basePrompt = formatApprovalPrompt(this.tool, resolvedArgs, approvalCheck.reason);
const safetyPrompt =
pendingSafetyChecks.length > 0
? `${basePrompt}\nProvider safety checks:\n${safetyCheckLines(pendingSafetyChecks).join("\n")}`
: basePrompt;View on GitHub (pinned to 9690622007)
Solutions
- Run the tool call inside an interactive UI (TUI) so the safety-check prompt can be shown
- Route execution through an embedding that provides a UI to the runner (hasUI() true)
- If safety checks are already approved upstream, set context.providerSafetyApproved so the gate is skipped
- Restructure the workflow so the flagged tool call is not issued headlessly
Defensive patterns
Strategy: validation
Validate before calling
if (!runner.hasUI()) throw new Error('provider safety checks require an interactive UI; re-run in TUI'); Try / catch
try { await tool.execute(params); } catch (err) {
if (err instanceof Error && err.message.includes('pending provider safety checks')) {
// surface guidance: run interactively or pre-approve
} else throw err;
} Prevention
- Never run safety-check-gated tools headlessly without a UI-backed runner
- Check runner.hasUI() before dispatching gated tool calls
- Keep provider-safety approval state (context.providerSafetyApproved) in sync in SDK embeddings
- Document to users that safety checks cannot be bypassed by yolo mode
When it happens
Trigger: Running tool execution headlessly (SDK, RPC, non-TUI embedding) with a tool whose provider returned pending safety checks; this.runner.hasUI() returns false while pendingSafetyChecks.length > 0.
Common situations: Headless scripts or CI invoking the agent SDK; RPC mode without an attached UI; running in a piped/non-TTY environment where the interactive prompt cannot render.
Related errors
- Tool "${this.tool.name}" requires approval but no interactiv
- failed to initialize AppKit
- Tool call denied by user: ${this.tool.name}
- Shared browser daemon unavailable (broker start or Chromium
- Created headless target ${targetId} did not expose a page
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/76cb6bc840023813.
Report an issue: GitHub.