Skip to main content

Fixed: "signal is aborted without reason" After Stopping an AG-UI Run

· 6 min read
Jagdish Kumawat
Founder @ Dewiride

My chat page had a Stop button that calls abortRun() on its AG-UI agent. Pressing it stopped the answer — and showed signal is aborted without reason in red, as if something had failed. That text is the browser's wording for a cancelled request: @ag-ui/client 1.0.4 ends a stopped run with its own RUN_ERROR event, code abort. Skipping that one code fixed it.

What I Was Doing​

I was building the chat page for Part 7 of the Microsoft Agent Framework series. It uses HttpAgent from @ag-ui/client 1.0.4 to stream the agent's answers, shows every RUN_ERROR event as a red message, and has a Stop button:

app/chat.tsx (the first version)
await agent.runAgent(
{},
{
onMessagesChanged: ({ messages }) => setMessages([...messages]),
onRunErrorEvent: ({ event }) => setError(event.message),
},
);
app/chat.tsx (the Stop button's handler)
function stop() {
agentRef.current?.abortRun();
}

I asked for something long, Explain step by step how to set up a VPN connection on Windows 11, in detail, and pressed Stop while the answer was still streaming in.

What I Expected​

The answer stopping where it was, the Send button coming back, and nothing else: stopping was my choice.

What I Got​

The answer stopped, and a red error appeared under it:

The chat page after pressing Stop: the VPN answer cut off at step 5, followed by a red message reading signal is aborted without reason

Nothing had failed: the agent, the server route and the browser all did what I asked. The page just reported it as an error.

What I Checked​

Where the words come from. Neither my code nor the agent has the text signal is aborted without reason. It is how Chromium-based browsers describe a cancelled request. In Chromium 158, cancelling an AbortController without giving a reason produces this:

Browser console
const controller = new AbortController();
controller.abort();
controller.signal.reason.name; // "AbortError"
controller.signal.reason.message; // "signal is aborted without reason"

A fetch cancelled that way rejects with the same AbortError. abortRun() cancels HttpAgent's own abort controller, without a reason.

How the error reached onRunErrorEvent. In @ag-ui/client 1.0.4, the code that reads the response stream handles an AbortError specially. Formatted, from dist/index.mjs:

@ag-ui/client 1.0.4 (formatted, with readable names)
error: (error) => {
if (error?.name === "AbortError") {
events.next({
type: EventType.RUN_ERROR,
message: error.message || "Request aborted",
code: "abort",
rawEvent: error,
});
complete();
return;
}
return fail(error);
},

So a stopped run doesn't throw: it ends with a RUN_ERROR event that the client creates itself, with the browser's message and the code abort. My onRunErrorEvent showed every RUN_ERROR, including this one.

Why It Happens​

The AG-UI client ends a cancelled run with an event of its own, so everything listening learns that the run is over. It uses the event type for errors, RUN_ERROR, and marks it with code: "abort". A page that shows every RUN_ERROR treats the user's own Stop as a failure, and the message it shows is the browser's technical wording for a cancelled request.

The Fix​

Show RUN_ERROR messages, except the one with the code abort:

app/chat.tsx
await agent.runAgent(
{},
{
onMessagesChanged: ({ messages }) => setMessages([...messages]),
onRunErrorEvent: ({ event }) => {
// Stop ends the run with the client's own "abort" event: not an error.
if (event.code !== "abort") {
setError(event.message);
}
},
},
);

Real errors still show: when the agent's API was down, the route's RUN_ERROR, The agent isn't available right now. Please try again in a moment., appeared as before, because it has no abort code.

After the Fix​

The same long question, the same Stop:

The chat page after pressing Stop with the fix: the VPN answer cut off mid-list, the Send button back next to the text box, and no error message

The answer ends where it was, Send is back, and no error appears. The two screenshots come from two runs, so the answer's wording differs.

Common Mistakes​

MistakeWhat happensDo this instead
Showing every RUN_ERRORPressing Stop shows signal is aborted without reasonSkip events with code: "abort"
Matching the message text instead of the codeOther environments word a cancelled request differently — in Node.js the same event says This operation was abortedCheck event.code
Ignoring every RUN_ERROR to hide this oneReal failures, such as the agent being down, disappear tooSkip only abort

Troubleshooting​

SymptomLikely causeFix
signal is aborted without reason after StopThe page shows the client's abort eventSkip code: "abort" in onRunErrorEvent
Request aborted after StopThe same event, where the cancellation had no messageThe same fix
No error appears when the agent is really downAll RUN_ERROR events are ignoredShow every code except abort

FAQ​

Why doesn't runAgent throw when I stop it?​

The client turns the cancellation into a RUN_ERROR event and completes the run, so runAgent returns normally. Errors that never become events, such as a route that can't be reached, are still thrown.

Does Stop also stop the agent?​

Stopping cancels the browser's request. In the series, the server route passes the same cancellation on to its call to the agent, so the agent's API stops too (Part 6).

Conclusion​

signal is aborted without reason after pressing Stop isn't an error in your app: it is the browser's wording for the cancellation you asked for, delivered by @ag-ui/client as a RUN_ERROR event with the code abort. Check event.code in onRunErrorEvent and skip abort; every other error still reaches the user.

Additional Resources​