can1357/oh-my-pi · warning · AbortError

AbortError

Error message

AbortError

What it means

After the event loop finishes, if the caller's AbortSignal is aborted the library throws a plain AbortError — the stream ended because the caller cancelled, not because the model finished. This distinguishes cancellation from normal completion and from model-reported stop reasons.

Source

Thrown at packages/ai/src/providers/amazon-bedrock.ts:575

								ev.stopReason === "guardrail_intervened"
									? `Response blocked by Amazon Bedrock guardrail (stop reason: ${ev.stopReason}).`
									: ev.stopReason === "content_filtered"
										? `Response filtered by Amazon Bedrock content filters (stop reason: ${ev.stopReason}).`
										: `Generation failed with stop reason: ${ev.stopReason ?? "unknown"}`;
						}
						break;
					}
					case "metadata": {
						handleMetadata(payload as MetadataEvent, model, output);
						break;
					}
					default:
						// Unknown event types (Bedrock may add new ones) — ignore.
						break;
				}
			}

			if (options.signal?.aborted) throw new AIError.AbortError();

			if (output.stopReason === "error" || output.stopReason === "aborted") {
				throw new AIError.BedrockApiError(output.errorMessage ?? "An unknown error occurred", 0);
			}

			output.duration = performance.now() - startTime;
			if (firstTokenTime) output.ttft = firstTokenTime - startTime;
			stream.push({ type: "done", reason: output.stopReason, message: output });
			stream.end();
		} catch (error) {
			for (const block of output.content) {
				if (block.type === "toolCall") clearStreamingPartialJson(block);
			}
			let baseMessage: string;
			try {
				baseMessage = error instanceof Error ? error.message : (JSON.stringify(error) ?? String(error));
			} catch {
				baseMessage = String(error);

View on GitHub (pinned to 9690622007)

Solutions

  1. Check options.signal.aborted to confirm this is your own cancellation — handle as a normal cancel, not an API failure
  2. Adjust timeout AbortControllers if streams are legitimately long; use generous idle-based timeouts instead of total-duration ones
  3. Catch AbortError separately from BedrockApiError to preserve partial output if desired
  4. Avoid aborting during teardown you want to complete — detach the signal before cleanup

Example fix

// before
const controller = new AbortController();
setTimeout(() => controller.abort(), 30000); // aborts valid long generations
// after
const controller = new AbortController();
const onStall = () => controller.abort();
stream.on('progress', () => resetIdleTimer(onStall)); // idle-based instead
try { await run(controller.signal); }
catch (e) { if (e.name === 'AbortError') return partialOutput; throw e; }
Defensive patterns

Strategy: try-catch

Validate before calling

if (options.signal?.aborted) return; // don't start a doomed stream

Type guard

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

Try / catch

try {
  for await (const ev of streamBedrock({ ...options, signal })) consume(ev);
} catch (e) {
  if (isAbortError(e)) return partialOutput; // caller cancelled — normal path
  if (e instanceof AIError.BedrockApiError && e.message.includes("unknown error")) handleModelError(e);
  throw e;
}

Prevention

When it happens

Trigger: Aborting the signal while streamBedrock is still iterating events; the signal aborting between the last event and stream completion; caller cancellation (timeout, unmount, user stop) mid-generation.

Common situations: UI stop buttons aborting generation; request timeouts firing just before the model would have finished; pipeline teardown cancelling in-flight streams.

Related errors


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