{"record":{"id":"b1e600719f16b3f6","repo":"stablyai/orca","slug":"request-timed-out-after-timeoutms-1000-second","errorCode":null,"errorMessage":"request timed out after ${timeoutMs / 1000} seconds","messagePattern":"request timed out after (.+?) seconds","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/main/ipc/feedback.ts","lineNumber":128,"sourceCode":"  readResponse?: (response: Response) => Promise<void>\n): Promise<Response> {\n  const controller = new AbortController()\n  // Why: a silent endpoint must not leave feedback IPC pending forever.\n  const timeout = setTimeout(() => controller.abort(), timeoutMs)\n  try {\n    const init: RequestInit = {\n      method: 'POST',\n      ...feedbackRequestBodyInit(body),\n      signal: controller.signal\n    }\n    const response = await net.fetch(url, init)\n    if (readResponse) {\n      await readResponse(response)\n    }\n    // Why: a response parser may tolerate malformed legacy bodies, but it must\n    // not turn the deadline's aborted body into a confirmed delivery.\n    if (controller.signal.aborted) {\n      throw new Error(`request timed out after ${timeoutMs / 1000} seconds`)\n    }\n    return response\n  } catch (error) {\n    // Why: Electron and Node report AbortError differently; keep deadline logs stable.\n    if (controller.signal.aborted) {\n      throw new Error(`request timed out after ${timeoutMs / 1000} seconds`)\n    }\n    throw error\n  } finally {\n    clearTimeout(timeout)\n  }\n}\n\nfunction feedbackRequestBodyInit(body: FeedbackSubmitBody): Pick<RequestInit, 'body' | 'headers'> {\n  if (!body.diagnosticBundle && !body.images?.length) {\n    return {\n      headers: { 'Content-Type': 'application/json' },\n      body: JSON.stringify(body)","sourceCodeStart":110,"sourceCodeEnd":146,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/src/main/ipc/feedback.ts#L110-L146","documentation":"Thrown on the happy path of `postFeedback` after `readResponse` completes: if `controller.signal.aborted` is true, the AbortController deadline fired even though the response parser finished. The code normalizes the deadline as an explicit timeout error so a parser tolerating a half-aborted body cannot be mistaken for a confirmed delivery. Default deadline is `FEEDBACK_REQUEST_TIMEOUT_MS = 10_000` ms (or 60s for attachments).","triggerScenarios":"`net.fetch` plus `readResponse` took longer than `timeoutMs` (10s for plain feedback, 60s for image attachments), and the AbortController fired during or just after body parsing.","commonSituations":"Slow or saturated feedback endpoint; large image attachments exceeding 60s on a poor link; an endpoint that streams a body slowly enough that the deadline elapses mid-read.","solutions":["Retry the feedback submission with a higher `timeoutMs` only if the payload is legitimately large (attachments).","Reduce attachment size/count so the request completes within the 60s attachment deadline.","Check network connectivity; a consistently timing-out endpoint indicates a server-side or connectivity problem, not a client bug."],"exampleFix":"// before\nconst res = await postFeedback(url, body)  // 10s default, times out on big payload\n\n// after\nconst res = await postFeedback(url, body, FEEDBACK_ATTACHMENT_REQUEST_TIMEOUT_MS, readResponse)","handlingStrategy":"retry","validationCode":"// For large payloads, request a longer deadline up front.\nconst timeoutMs = hasImages ? FEEDBACK_ATTACHMENT_REQUEST_TIMEOUT_MS : FEEDBACK_REQUEST_TIMEOUT_MS\nawait postFeedback(url, body, timeoutMs, readResponse)","typeGuard":"function isTimeoutError(e: unknown): boolean {\n  return e instanceof Error && /^request timed out after/.test(e.message)\n}","tryCatchPattern":"try {\n  await postFeedback(url, body, timeoutMs, readResponse)\n} catch (e) {\n  if (e instanceof Error && /^request timed out after/.test(e.message)) {\n    // only retry once, with a longer deadline and/or smaller payload\n    await postFeedback(url, body, timeoutMs * 2, readResponse)\n    return\n  }\n  throw e\n}","preventionTips":["Pick a timeout matched to payload size: 10s for plain feedback, 60s for attachments.","Shrink images before upload to stay well under the deadline.","Do not retry indefinitely; one bounded retry with a larger deadline is enough."],"tags":["feedback","network","timeout","abortcontroller","http"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}