can1357/oh-my-pi · warning · AbortError

Request was aborted.

Error message

Request was aborted.

What it means

An AbortError thrown by AnthropicApiError.fromResponse when the error-response body cannot be read (body locked by another consumer or missing) and the caller-supplied AbortSignal is already aborted. The library reports the abort as the real cause rather than surfacing a meaningless empty-body HTTP error.

Source

Thrown at packages/ai/src/error/classes.ts:104

};

/** Non-2xx response from the Anthropic API. */
export class AnthropicApiError extends ProviderHttpError {
	declare readonly headers: Headers;
	readonly requestId: string | null;

	constructor(status: number, message: string, headers: Headers) {
		super(message, status, { headers });
		this.name = "AnthropicApiError";
		this.requestId = headers.get("request-id");
	}

	static async fromResponse(response: Response, signal?: AbortSignal): Promise<AnthropicApiError> {
		// Avoid getReader() throwing when another consumer already owns the body.
		const reader = response.body?.locked ? undefined : response.body?.getReader();

		if (!reader) {
			if (signal?.aborted) throw new AbortError("Request was aborted.");
			const detail = "status code (no body)";
			return new AnthropicApiError(response.status, `${response.status} ${detail}`, response.headers);
		}

		let aborted = false;
		let timedOut = false;
		let readerCancelled = false;
		const cancelReader = () => {
			if (readerCancelled) return;
			readerCancelled = true;
			void reader.cancel().catch(() => {});
		};
		const onAbort = () => {
			if (aborted) return;
			aborted = true;
			cancelReader();
		};
		if (signal?.aborted) onAbort();

View on GitHub (pinned to 9690622007)

Solutions

  1. Check signal.aborted before treating this as an API failure — it is a cancellation, not a server error
  2. Avoid aborting the signal while the error response is still being read; cancel only before the fetch resolves or after handling completes
  3. Ensure only one consumer reads response.body; let fromResponse own it
  4. Catch AbortError distinctly from AnthropicApiError to implement clean cancellation UX

Example fix

// before
const err = await AnthropicApiError.fromResponse(res, signal); // throws AbortError
// after
try {
  const err = await AnthropicApiError.fromResponse(res, signal);
} catch (e) {
  if (e instanceof AbortError || signal?.aborted) return handleCancelled();
  throw e;
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (signal?.aborted) return handleCancelled(); // check before calling fromResponse

Type guard

function isAbort(e: unknown): e is Error & { name: "AbortError" } {
  return e instanceof Error && e.name === "AbortError";
}

Try / catch

try {
  const apiErr = await AnthropicApiError.fromResponse(res, signal);
  handleApiError(apiErr);
} catch (e) {
  if (isAbort(e) || signal?.aborted) return; // cancellation, not API failure
  throw e;
}

Prevention

When it happens

Trigger: Passing an AbortSignal that is aborted before/while fromResponse reads an error response; reading the response body from two consumers so the reader is unavailable and the signal fires; request cancellation racing with a non-2xx response.

Common situations: User cancels a request in a UI at the same moment the API returns an error; a timeout AbortController fires during error-body download; sharing one Response body between logging and error handling.

Related errors


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