paperclipai/paperclip · error · NativeProviderTerminalFailure
provider_turn_failed
provider_turn_failed
Error message
provider_turn_failed
What it means
A provider turn failed terminally and the runtime throws NativeProviderTerminalFailure. The code is the provider-supplied failure code when it is a string, otherwise the generic 'provider_turn_failed'. The runtime separately detects model-rejection text and rewrites the failure as native_provider_model_rejected; recoverable failures are not turned terminal.
Source
Thrown at packages/paperclip-runner/src/native-session-runtime.ts:2367
const failure =
payload.error && typeof payload.error === "object"
? (payload.error as Record<string, unknown>)
: payload;
const message =
typeof failure.message === "string"
? failure.message.slice(0, 2_000)
: "Provider turn failed";
const recoverable =
failure.recoverable === true || payload.recoverable === true;
// Retain the older consumer's permanent-model classification while
// preserving structured provider metadata. A provider explicitly
// permitting retry must not become permanent merely from its text.
const modelRejected =
!recoverable &&
/issue with the selected model|model_not_found|invalid model|model[^\n]*(?:does not exist|not found|not supported)/i.test(
message,
);
throw new NativeProviderTerminalFailure(
typeof failure.code === "string"
? failure.code
: "provider_turn_failed",
recoverable,
modelRejected
? `native_provider_model_rejected: ${message}`
: message,
);
}
if (settledCompletion === null && options.resolveMissingResult) {
const recoveredResult = await options.resolveMissingResult({
turnId: terminalEvent.turnId ?? null,
terminalEvent,
});
signal.throwIfAborted();
if (recoveredResult !== null) {
settledCompletion = {
result: recoveredResult,View on GitHub (pinned to 01ad858492)
Solutions
- Inspect the failure message for the real provider-side cause
- Retry the run — if the failure was actually transient, this was misclassified as terminal
- Check provider status/region outages and API version compatibility
- Upgrade the runtime/provider adapter so failure codes are surfaced as strings
Defensive patterns
Strategy: retry
Validate before calling
// validate provider response has a code before treating as terminal
if (failure && typeof failure.code !== 'string' && !failure.message) logWarning('unclassified provider failure'); Type guard
const hasCode = (f) => !!f && typeof f.code === 'string';
Try / catch
try { await providerTurn() } catch (e) { if (e instanceof NativeProviderTerminalFailure && e.recoverable) retry(); else throw e; } Prevention
- Keep provider adapters updated so failure codes are surfaced as strings
- Wrap turn calls in retry with backoff for recoverable failures
- Alert on provider_turn_failed spikes to catch provider outages
- Match provider error-message changes against the model-rejection regex when upgrading
When it happens
Trigger: Calling a provider turn where the provider returns a failure with no string code and the message does not match the model-rejection regex, and the failure is not recoverable.
Common situations: Provider API errors without structured codes (HTML error pages, truncated responses); transient-but-unrecoverable provider outages; malformed provider stream.
Related errors
- provider turn ended with status ${turn.status}
- invalid_provider
- eval-session provider is unsupported by CapabilityLiveSessio
- The bridge host reached its reserved process body byte ceili
- provider-reported cost limit exceeded
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10).
Data as JSON: /api/errors/73f88a7617b44a41.
Report an issue: GitHub.