Fixed: "signal is aborted without reason" After Stopping an AG-UI Run
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:
await agent.runAgent(
{},
{
onMessagesChanged: ({ messages }) => setMessages([...messages]),
onRunErrorEvent: ({ event }) => setError(event.message),
},
);
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:

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:
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:
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:
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 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
| Mistake | What happens | Do this instead |
|---|---|---|
Showing every RUN_ERROR | Pressing Stop shows signal is aborted without reason | Skip events with code: "abort" |
| Matching the message text instead of the code | Other environments word a cancelled request differently — in Node.js the same event says This operation was aborted | Check event.code |
Ignoring every RUN_ERROR to hide this one | Real failures, such as the agent being down, disappear too | Skip only abort |
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| signal is aborted without reason after Stop | The page shows the client's abort event | Skip code: "abort" in onRunErrorEvent |
| Request aborted after Stop | The same event, where the cancellation had no message | The same fix |
| No error appears when the agent is really down | All RUN_ERROR events are ignored | Show 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
- AG-UI on GitHub — the protocol and the TypeScript client.
- MDN: AbortController.abort() — what an abort without a reason produces.
- Part 7: Build a Streaming Chat Page with the AG-UI Client — the chat page with its Stop button.
