can1357/oh-my-pi · warning
Request was aborted
Error message
Request was aborted
What it means
The agent loop throws this when a streaming response ends (or is aborted) and the only accumulated content is empty tool calls while the loop's abort signal has fired. It converts an abort that would otherwise be silently swallowed into an explicit error so the loop's catch block can record the run as aborted. It only fires on the path where all partial items were empty tool calls and loopSignal.aborted is true.
Source
Thrown at packages/agent/src/agent.ts:1598
}
// Emit to listeners
this.#emit(event);
}
// Handle any remaining partial message
if (partial && partial.role === "assistant" && Array.isArray(partial.content) && partial.content.length > 0) {
const onlyEmpty = !partial.content.some(
c =>
(c.type === "thinking" && c.thinking.trim().length > 0) ||
(c.type === "text" && c.text.trim().length > 0) ||
(c.type === "toolCall" && c.name.trim().length > 0),
);
if (!onlyEmpty) {
this.appendMessage(partial);
} else {
if (loopSignal.aborted) {
throw new Error("Request was aborted");
}
}
}
} catch (err) {
const stoppedForAbort = loopSignal.aborted;
const errorMessage = stoppedForAbort
? abortReasonText(loopSignal)
: err instanceof Error
? err.message
: String(err);
const shouldEmitVisibleError = !stoppedForAbort;
const assistantPartial = partial?.role === "assistant" ? partial : undefined;
const hadAssistantStart = assistantPartial !== undefined;
// Same contract as the normal drain in `#emitCursorSplitAssistantMessage`:
// a transformer still in flight must be awaited before the payload is
// snapshotted, or its rewrite patches an entry this catch path already
// detached and the original is persisted instead. A provider error is
// exactly when a transform is most likely to be mid-flight.View on GitHub (pinned to 9690622007)
Solutions
- Check the AbortSignal you passed (options.signal / loop signal) — if you aborted, handle this error as expected control flow, not a bug
- Catch the error and treat loopSignal.aborted (or err message 'Request was aborted') as a graceful-stop path rather than retrying
- If you did NOT abort, verify no shared AbortController/timeout is cancelling the request early (e.g. HTTP client timeouts, parent signal propagation)
- Retry the prompt with a fresh call if the abort was unintentional and the underlying cause (timeout, shutdown) is resolved
Example fix
// before
await agent.prompt("do the thing", { signal: controller.signal }); // throws on Ctrl+C
// after
try {
await agent.prompt("do the thing", { signal: controller.signal });
} catch (err) {
if (controller.signal.aborted) return; // graceful stop
throw err;
} Defensive patterns
Strategy: try-catch
Validate before calling
// before prompting
if (signal?.aborted) {
throw new DOMException("Aborted before start", "AbortError");
} Type guard
function isAbortError(err: unknown): boolean {
return err instanceof Error && /abort/i.test(err.message);
} Try / catch
try {
await agent.prompt(text, { signal });
} catch (err) {
if (signal.aborted || isAbortError(err)) {
return; // graceful stop
}
throw err;
} Prevention
- Always pass a dedicated AbortController per run and inspect signal.aborted in catch blocks
- Treat 'Request was aborted' as control flow, not a failure to retry
- Audit timeout chains so client timeouts don't fire mid tool-call-only turns
When it happens
Trigger: Calling agent.prompt()/run() and aborting the loop via an AbortSignal/stop() while the model was streaming a response consisting solely of empty tool-call items; the stream ends with no usable content and loopSignal.aborted is true.
Common situations: User hits Ctrl+C / stop button mid-stream right as the model emits tool calls; a timeout cancels the request during a tool-call-only turn; programmatic cancellation races with the stream finishing.
Related errors
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/c139746768022802.
Report an issue: GitHub.