{"record":{"id":"d493eec22379848c","repo":"can1357/oh-my-pi","slug":"aborterror","errorCode":null,"errorMessage":"AbortError","messagePattern":"AbortError","errorType":"exception","errorClass":"AbortError","httpStatus":null,"severity":"warning","filePath":"packages/ai/src/providers/amazon-bedrock.ts","lineNumber":575,"sourceCode":"\t\t\t\t\t\t\t\tev.stopReason === \"guardrail_intervened\"\n\t\t\t\t\t\t\t\t\t? `Response blocked by Amazon Bedrock guardrail (stop reason: ${ev.stopReason}).`\n\t\t\t\t\t\t\t\t\t: ev.stopReason === \"content_filtered\"\n\t\t\t\t\t\t\t\t\t\t? `Response filtered by Amazon Bedrock content filters (stop reason: ${ev.stopReason}).`\n\t\t\t\t\t\t\t\t\t\t: `Generation failed with stop reason: ${ev.stopReason ?? \"unknown\"}`;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"metadata\": {\n\t\t\t\t\t\thandleMetadata(payload as MetadataEvent, model, output);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tdefault:\n\t\t\t\t\t\t// Unknown event types (Bedrock may add new ones) — ignore.\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (options.signal?.aborted) throw new AIError.AbortError();\n\n\t\t\tif (output.stopReason === \"error\" || output.stopReason === \"aborted\") {\n\t\t\t\tthrow new AIError.BedrockApiError(output.errorMessage ?? \"An unknown error occurred\", 0);\n\t\t\t}\n\n\t\t\toutput.duration = performance.now() - startTime;\n\t\t\tif (firstTokenTime) output.ttft = firstTokenTime - startTime;\n\t\t\tstream.push({ type: \"done\", reason: output.stopReason, message: output });\n\t\t\tstream.end();\n\t\t} catch (error) {\n\t\t\tfor (const block of output.content) {\n\t\t\t\tif (block.type === \"toolCall\") clearStreamingPartialJson(block);\n\t\t\t}\n\t\t\tlet baseMessage: string;\n\t\t\ttry {\n\t\t\t\tbaseMessage = error instanceof Error ? error.message : (JSON.stringify(error) ?? String(error));\n\t\t\t} catch {\n\t\t\t\tbaseMessage = String(error);","sourceCodeStart":557,"sourceCodeEnd":593,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/ai/src/providers/amazon-bedrock.ts#L557-L593","documentation":"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.","triggerScenarios":"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.","commonSituations":"UI stop buttons aborting generation; request timeouts firing just before the model would have finished; pipeline teardown cancelling in-flight streams.","solutions":["Check options.signal.aborted to confirm this is your own cancellation — handle as a normal cancel, not an API failure","Adjust timeout AbortControllers if streams are legitimately long; use generous idle-based timeouts instead of total-duration ones","Catch AbortError separately from BedrockApiError to preserve partial output if desired","Avoid aborting during teardown you want to complete — detach the signal before cleanup"],"exampleFix":"// before\nconst controller = new AbortController();\nsetTimeout(() => controller.abort(), 30000); // aborts valid long generations\n// after\nconst controller = new AbortController();\nconst onStall = () => controller.abort();\nstream.on('progress', () => resetIdleTimer(onStall)); // idle-based instead\ntry { await run(controller.signal); }\ncatch (e) { if (e.name === 'AbortError') return partialOutput; throw e; }","handlingStrategy":"try-catch","validationCode":"if (options.signal?.aborted) return; // don't start a doomed stream","typeGuard":"function isAbortError(e: unknown): e is Error & { name: \"AbortError\" } {\n  return e instanceof Error && e.name === \"AbortError\";\n}","tryCatchPattern":"try {\n  for await (const ev of streamBedrock({ ...options, signal })) consume(ev);\n} catch (e) {\n  if (isAbortError(e)) return partialOutput; // caller cancelled — normal path\n  if (e instanceof AIError.BedrockApiError && e.message.includes(\"unknown error\")) handleModelError(e);\n  throw e;\n}","preventionTips":["Check signal.aborted first in every stream error handler — abort errors are expected control flow","Prefer idle/stall-based timeouts over total-duration aborts for long generations","Keep partial output accumulated so cancellation still yields usable text","Use one AbortController per request to prevent cross-request cancels"],"tags":["abort","cancellation","bedrock","streaming"],"backgroundTag":"request-aborted","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}