can1357/oh-my-pi · error · ProviderResponseError

An unknown error occurred

Error message

An unknown error occurred

What it means

AIError.ProviderResponseError is thrown in the Anthropic streaming provider when a completed stream ends with output.stopReason of 'aborted' or 'error'. The provider ran the request but the upstream returned a terminal error state instead of normal completion; output.errorMessage is used when the API supplied one, otherwise the generic 'An unknown error occurred' fallback is used. It carries kind:'output' and the provider name so callers can distinguish provider-side failures from request-configuration failures.

Source

Thrown at packages/ai/src/providers/anthropic.ts:2695

						// A stop_reason arrived via message_delta, so generation finished;
						// only the trailing message_stop frame is missing (non-conforming
						// gateway). Degrade to best-effort instead of discarding the turn.
						reportAnthropicEnvelopeAnomaly("stream ended before message_stop");
					}
					if (openBlocks.size > 0) {
						for (const [openIndex, openBlock] of openBlocks) {
							reportAnthropicEnvelopeAnomaly(
								`stream ended with an unterminated ${openBlock.kind} block at index ${openIndex}`,
							);
							if (openBlock.kind === "ignored" || openBlock.contentIndex < 0) continue;
							const danglingBlock = blocks[openBlock.contentIndex];
							if (danglingBlock) finalizeStreamBlock(danglingBlock, openBlock.contentIndex);
						}
						openBlocks.clear();
					}

					if (output.stopReason === "aborted" || output.stopReason === "error") {
						throw new AIError.ProviderResponseError(output.errorMessage ?? "An unknown error occurred", {
							provider: model.provider,
							kind: "output",
						});
					}
					break;
				} catch (streamError) {
					const streamFailure = activeAbortTracker.getLocalAbortReason() ?? streamError;
					if (
						!disableStrictTools &&
						firstTokenTime === undefined &&
						hasStrictAnthropicTools(params) &&
						AIError.isGrammarError(streamFailure)
					) {
						// Log-only: the retried turn must not carry an errorMessage on
						// success (consumers treat its presence as failure).
						logger.warn("anthropic: strict tools rejected, retrying without strict tools", {
							model: model.id,
							error: await finalizeErrorMessage(streamFailure, rawRequestDump),

View on GitHub (pinned to 9690622007)

Solutions

  1. Inspect the full output object / provider logs around the throw to find the real upstream stopReason and any error event payload, since 'An unknown error occurred' hides the cause
  2. Retry the request with backoff if stopReason was 'error' due to overloaded_error or a transient Anthropic incident (check status.anthropic.com)
  3. Catch AIError.ProviderResponseError, check the kind==='output' and provider fields, and surface a retryable failure to your app instead of crashing
  4. If aborted unexpectedly, check for request cancellation (AbortSignal) or gateway/proxy timeouts in your infrastructure
  5. Update @oh-my-pi/pi-ai in case the missing errorMessage parsing has been fixed in a newer version

Example fix

// before: raw crash on transient overload
const result = await session.prompt(model, messages);
// after: catch provider output errors and retry
try {
  const result = await session.prompt(model, messages);
} catch (err) {
  if (err instanceof AIError.ProviderResponseError && err.kind === "output") {
    // log err.provider + stopReason, retry with backoff
  }
  throw err;
}
Defensive patterns

Strategy: try-catch

Type guard

function isProviderOutputError(err: unknown): err is AIError.ProviderResponseError {
  return err instanceof AIError.ProviderResponseError && err.kind === "output";
}

Try / catch

try {
  const result = await session.prompt(model, messages);
} catch (err) {
  if (err instanceof AIError.ProviderResponseError && err.kind === "output") {
    logger.warn("anthropic stream ended in error state", { provider: err.provider });
    // retry with backoff or surface a user-facing failure
    return;
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling an Anthropic model (streaming path in packages/ai/src/providers/anthropic.ts) when the stream finishes with stopReason 'aborted' or 'error' and no errorMessage text was captured — e.g. the upstream aborted mid-generation, an overloaded_error or other API error event terminated the stream without a parsed message, or an internal error event carried no payload.

Common situations: Anthropic API returns overloaded_error (529) or a transient internal error mid-stream; a proxy/gateway truncates the stream; the request was cancelled upstream and surfaced as 'aborted' with no message; SDK version where the error event's message field isn't parsed into output.errorMessage, so only the fallback string appears.

Related errors


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