{"record":{"id":"f6d33dad7461fa10","repo":"tursodatabase/turso","slug":"query-timed-out","errorCode":null,"errorMessage":"Query timed out","messagePattern":"Query timed out","errorType":"exception","errorClass":"TimeoutError","httpStatus":null,"severity":"error","filePath":"serverless/javascript/src/protocol.ts","lineNumber":274,"sourceCode":"  };\n}\n\n/** Per-query options. Override the session-level defaults for a single call. */\nexport interface QueryOptions {\n  /** Per-query timeout in milliseconds. Overrides defaultQueryTimeout for this call. */\n  queryTimeout?: number;\n  /**\n   * Extra HTTP headers attached to this request only. Applied after the\n   * standard headers and any session-level `requestHeaders`, so they can\n   * override both. Passing the `Host` key (case-insensitive) throws —\n   * fetch forbids setting it.\n   */\n  requestHeaders?: Record<string, string>;\n}\n\nfunction wrapAbortError(error: unknown): never {\n  if (error instanceof Error && (error.name === 'AbortError' || error.name === 'TimeoutError')) {\n    throw new TimeoutError('Query timed out');\n  }\n  throw error;\n}\n\nexport async function executeCursor(\n  ctx: HttpContext,\n  request: CursorRequest,\n  signal?: AbortSignal\n): Promise<{ response: CursorResponse; entries: AsyncGenerator<CursorEntry> }> {\n  let response: Response;\n  try {\n    response = await fetch(`${ctx.url}/v3/cursor`, buildFetchOptions(ctx, JSON.stringify(request), signal));\n  } catch (error) {\n    wrapAbortError(error);\n  }\n\n  if (!response.ok) {\n    let errorMessage = `HTTP error! status: ${response.status}`;","sourceCodeStart":256,"sourceCodeEnd":292,"githubUrl":"https://github.com/tursodatabase/turso/blob/bad083fafbefdeae9a42ec19bdaaad8918dcf411/serverless/javascript/src/protocol.ts#L256-L292","documentation":"TimeoutError (a DatabaseError subclass with code 'TIMEOUT') thrown when the fetch backing a request is aborted because it exceeded its deadline. The deadline is QueryOptions.queryTimeout for a single call or SessionConfig.defaultQueryTimeout for the session, implemented with AbortSignal.timeout(); both fetch aborts and mid-stream read aborts are wrapped into this error.","triggerScenarios":"A query running longer than the configured timeout in milliseconds; a timeout value written in the wrong unit (5 intended as seconds is 5ms); slow database cold starts or network stalls under a tight defaultQueryTimeout; a queryTimeout passed to any of run/get/all/exec/batch/pragma/prepare or transaction handles.","commonSituations":"Setting defaultQueryTimeout: 5 expecting seconds; large table scans or unindexed joins exceeding a conservative default; edge deployments physically far from the database; retries after the abort arrive but the session baton was reset so the next query starts fresh.","solutions":["Raise or correct the timeout: pass a larger queryTimeout for known-slow calls, or a larger defaultQueryTimeout — both are milliseconds","Optimize the query (add indexes, add LIMIT, use EXPLAIN QUERY PLAN) so it finishes under the deadline","Catch TimeoutError (code 'TIMEOUT') and retry with backoff for transiently slow queries"],"exampleFix":"// before\nconst db = connect({ url, authToken, defaultQueryTimeout: 5 }); // meant 5 seconds, is 5ms\n\n// after\nconst db = connect({ url, authToken, defaultQueryTimeout: 5000 }); // 5 seconds, in milliseconds","handlingStrategy":"retry","validationCode":"const timeout = config.defaultQueryTimeout;\nif (timeout != null && (timeout < 100 || !Number.isFinite(timeout))) {\n  console.warn(\"defaultQueryTimeout is in MILLISECONDS;\", timeout, \"looks wrong\");\n}","typeGuard":"const isTimeoutError = (e: unknown): boolean =>\n  e instanceof Error && (e as { code?: string }).code === \"TIMEOUT\";","tryCatchPattern":"async function withRetry<T>(fn: () => Promise<T>, tries = 3): Promise<T> {\n  for (let i = 1; ; i++) {\n    try {\n      return await fn();\n    } catch (e) {\n      if (!(e instanceof Error && (e as { code?: string }).code === \"TIMEOUT\") || i === tries) throw e;\n      await new Promise((r) => setTimeout(r, 100 * 2 ** i));\n    }\n  }\n}\nconst rows = await withRetry(() => db.all(\"SELECT ...\"));","preventionTips":["Remember timeouts are milliseconds: 5000 means 5 seconds","Set a per-call queryTimeout for known-slow maintenance queries instead of raising the session default","Index and LIMIT slow queries; verify plans with EXPLAIN QUERY PLAN before shipping"],"tags":["timeout","configuration","network","javascript"],"backgroundTag":"query-timeout","analyzedSha":"bad083fafbefdeae9a42ec19bdaaad8918dcf411","analyzedAt":"2026-08-16T23:12:11.798Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}