{"record":{"id":"559a2270db71da2a","repo":"remix-run/react-router","slug":"method-call-aborted-without-an-abortsignal-r","errorCode":null,"errorMessage":"${method}() call aborted without an `AbortSignal.reason`: ${request.method} ${request.url}","messagePattern":"(.+?)\\(\\) call aborted without an `AbortSignal\\.reason`: (.+?) (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/react-router/lib/router/router.ts","lineNumber":5079,"sourceCode":"  return {\n    ...handlerContext,\n    statusCode: isRouteErrorResponse(error) ? error.status : 500,\n    errors: {\n      [errorBoundaryId]: error,\n    },\n  };\n}\n\nfunction throwStaticHandlerAbortedError(\n  request: Request,\n  isRouteRequest: boolean,\n) {\n  if (request.signal.reason !== undefined) {\n    throw request.signal.reason;\n  }\n\n  let method = isRouteRequest ? \"queryRoute\" : \"query\";\n  throw new Error(\n    `${method}() call aborted without an \\`AbortSignal.reason\\`: ${request.method} ${request.url}`,\n  );\n}\n\nfunction isSubmissionNavigation(\n  opts: BaseNavigateOrFetchOptions,\n): opts is SubmissionNavigateOptions {\n  return (\n    opts != null &&\n    ((\"formData\" in opts && opts.formData != null) ||\n      (\"body\" in opts && opts.body !== undefined))\n  );\n}\n\nfunction defaultNormalizePath(request: Request): Path {\n  let url = new URL(request.url);\n  return {\n    pathname: url.pathname,","sourceCodeStart":5061,"sourceCodeEnd":5097,"githubUrl":"https://github.com/remix-run/react-router/blob/7aea711dd1ae2bc5a076d13ff17291829690fa74/packages/react-router/lib/router/router.ts#L5061-L5097","documentation":"createStaticHandler's query()/queryRoute() aborts by re-throwing the AbortSignal's reason so callers can tell intentional cancellation apart from crashes. If the signal was aborted with no reason (a bare controller.abort()), throwStaticHandlerAbortedError (lib/router/router.ts:5092) throws this error because the framework cannot classify the abort.","triggerScenarios":"SSR request handling with a bare timeout abort: setTimeout(() => controller.abort(), 5000); calling abort() twice where the second call has no reason; a shared signal aborted by another consumer (e.g., a competitor fetch wins and aborts the common signal); environments whose abort implementation does not populate signal.reason.","commonSituations":"Node/edge SSR handlers adding request timeouts; React streaming SSR where an earlier render pass is aborted; Promise.race patterns that abort a shared controller; older fetch polyfills in Node that do not set signal.reason.","solutions":["Always abort with a reason: controller.abort(new Error('timeout')) or new DOMException('timeout', 'TimeoutError')","Check for double-abort: guard with if (signal.aborted) return before calling abort() again","Ensure only one owner aborts a shared signal","Catch the re-thrown reason in your handler and map known reasons to proper responses"],"exampleFix":"// before\nsetTimeout(() => controller.abort(), 5000)\n// after\nsetTimeout(() => controller.abort(new Error('SSR request timeout')), 5000)","handlingStrategy":"validation","validationCode":"// Single-owner abort helper that always attaches a reason\nfunction abortWithReason(ctrl: AbortController, reason: unknown) {\n  if (ctrl.signal.aborted) return;\n  ctrl.abort(reason instanceof Error ? reason : new Error(String(reason)));\n}\nsetTimeout(() => abortWithReason(controller, 'SSR timeout'), 5000);","typeGuard":null,"tryCatchPattern":"try {\n  const ctx = await staticHandler.query(request);\n} catch (e) {\n  if (request.signal.aborted) {\n    // distinguish intentional aborts: reason is re-thrown by the handler\n    return new Response('Aborted: ' + String(request.signal.reason), { status: 499 });\n  }\n  throw e;\n}","preventionTips":["Never call controller.abort() without an argument","Guard double aborts with if (signal.aborted) return","Give each in-flight SSR request its own controller; abort only from its owner","Log request.signal.reason in error reporting to classify aborts"],"tags":["ssr","abort-signal","createstatichandler","timeout","cancellation"],"backgroundTag":"abort-without-reason","analyzedSha":"7aea711dd1ae2bc5a076d13ff17291829690fa74","analyzedAt":"2026-08-18T18:04:14.938Z","contentChangedAt":"2026-08-18T18:04:14.938Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}