This is a submission for .
Every codebase has that one bug that looks tiny on paper and behaves like a small landmine underneath. This is the story of one of those bugs, and the fix I shipped for it in .
Bug Fix or Performance Improvement
Here is the problem in plain words.
fetchWithTimeout accepts a normal RequestInit object as one of its parameters, the same shape you would pass to the native fetch function. A caller can put anything in there, including their own AbortSignal, if they already have a reason to cancel the request early. Maybe the user pressed stop. Maybe the session ended. Maybe a parent operation was cancelled and everything underneath it should stop too.
The trouble was in how the utility built its own internal signal for the timeout. Internally it spread the caller's init object first, and then added its own timeout signal on top of it. That ordering meant the caller's signal was silently thrown away every single time. Whatever cancellation logic the calling code thought it had wired up simply did not exist anymore once the request reached fetchWithTimeout.
The practical effect was not a crash. It was quieter and arguably worse. A request that the rest of the system believed had been cancelled would keep running in the background until either it finished naturally or the internal timeout eventually caught up with it. Under normal load you would not notice. Under real load, with many concurrent sessions and channels, this is exactly the kind of leak that piles up, ties up connections, and makes the gateway feel sluggish for reasons that are hard to trace back to a root cause.
Code
Here is the pull request with the actual change.
Description
In src/utils/fetch-timeout.ts, the fetchWithTimeout wrapper is implemented as follows:
export async function fetchWithTimeout(
url: string,
init: RequestInit,
timeoutMs: number,
fetchFn: typeof fetch = fetch,
): Promise<Response> {
const { signal, cleanup } = buildTimeoutAbortSignal({
timeoutMs: Math.max(1, timeoutMs),
operation: "fetchWithTimeout",
url,
});
try {
return await fetchFn(url, { ...init, signal });
} finally {
cleanup();
}
}However, if the caller specifies a custom AbortSignal in init.signal (for instance, to cancel the request if a parent operation is aborted or the client disconnects), this signal is completely overridden by the new signal created in buildTimeoutAbortSignal.
Impact
The caller-provided AbortSignal is silently dropped and ignored, meaning that cancellations from the caller side will not abort the request during fetchWithTimeout.
Suggested Fix
Pass init.signal to buildTimeoutAbortSignal so that the timeout controller is chained to the parent signal:
const { signal, cleanup } = buildTimeoutAbortSignal({
timeoutMs: Math.max(1, timeoutMs),
operation: "fetchWithTimeout",
url,
signal: init.signal,
});openclaw/openclawOS Error 3) in the LanceDB integrationtopoteretes/cogneeNousResearch/hermes-agentTracer-Cloud/opensre
Closing Thoughts
Bugs like this one do not announce themselves. Nothing throws, nothing logs an error, the request just quietly keeps running when everyone assumed it had stopped. Finding it meant reading the helper function carefully enough to notice that object spread order was doing something nobody intended, and fixing it meant choosing a solution that respects every caller's expectations instead of just patching the one symptom I happened to see.
If you want to see more of what I build and fix, I am aniruddhaadak80 on , my writing on , and my day to day thoughts on X.
Small fixes, applied to the right place, are still real engineering. You do not need a rewrite to make a system more honest about what it promises to do.
Thanks for reading, and good luck smashing your own bugs this challenge.
Community-Analysen & Experten-Meinungen 0
Verwandte Story-Cluster & Quellen (Vektor-KI)
Ähnliche Beiträge
Auch interessante Nachrichten The Signal Nobody Heard, Fixing a Silent AbortSignal Bug in OpenClaw
Thematisch verwandte Begriffe: Signal, Nobody, Heard, Fixing · 6 Treffer
Critical N-able N-central Flaw Enables Pre-Auth Remote Code Execution
How I Turned Self-XSS into Reflected XSS (and Bypassed the WAF)
Black Box: The Chatbots | Life Raft | Ep 4 – podcast
Black Box: The Chatbots | 14 days | Ep 2 – podcast
Videos werden geladen ...
Beiträge werden geladen ...
Videos werden geladen ...
Beiträge werden geladen ...
Videos werden geladen ...
Beiträge werden geladen ...
Videos werden geladen ...
Beiträge werden geladen ...
Videos werden geladen ...
🔖 Gespeicherte Artikel
tsecurity.de App
Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.
Community Radar & Live Chat
Aktivitäten deiner Analysten
Neues Thema oder Eilmeldung einreichen
Reiche interessante Links, Zero-Days oder Debatten ein. Die Community entscheidet per Upvote über die Veröffentlichung.