tursodatabase/turso · error · TimeoutError
Query timed out
Error message
Query timed out
What it means
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.
Source
Thrown at serverless/javascript/src/protocol.ts:274
};
}
/** Per-query options. Override the session-level defaults for a single call. */
export interface QueryOptions {
/** Per-query timeout in milliseconds. Overrides defaultQueryTimeout for this call. */
queryTimeout?: number;
/**
* Extra HTTP headers attached to this request only. Applied after the
* standard headers and any session-level `requestHeaders`, so they can
* override both. Passing the `Host` key (case-insensitive) throws —
* fetch forbids setting it.
*/
requestHeaders?: Record<string, string>;
}
function wrapAbortError(error: unknown): never {
if (error instanceof Error && (error.name === 'AbortError' || error.name === 'TimeoutError')) {
throw new TimeoutError('Query timed out');
}
throw error;
}
export async function executeCursor(
ctx: HttpContext,
request: CursorRequest,
signal?: AbortSignal
): Promise<{ response: CursorResponse; entries: AsyncGenerator<CursorEntry> }> {
let response: Response;
try {
response = await fetch(`${ctx.url}/v3/cursor`, buildFetchOptions(ctx, JSON.stringify(request), signal));
} catch (error) {
wrapAbortError(error);
}
if (!response.ok) {
let errorMessage = `HTTP error! status: ${response.status}`;View on GitHub (pinned to bad083fafb)
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
Example fix
// before
const db = connect({ url, authToken, defaultQueryTimeout: 5 }); // meant 5 seconds, is 5ms
// after
const db = connect({ url, authToken, defaultQueryTimeout: 5000 }); // 5 seconds, in milliseconds Defensive patterns
Strategy: retry
Validate before calling
const timeout = config.defaultQueryTimeout;
if (timeout != null && (timeout < 100 || !Number.isFinite(timeout))) {
console.warn("defaultQueryTimeout is in MILLISECONDS;", timeout, "looks wrong");
} Type guard
const isTimeoutError = (e: unknown): boolean =>
e instanceof Error && (e as { code?: string }).code === "TIMEOUT"; Try / catch
async function withRetry<T>(fn: () => Promise<T>, tries = 3): Promise<T> {
for (let i = 1; ; i++) {
try {
return await fn();
} catch (e) {
if (!(e instanceof Error && (e as { code?: string }).code === "TIMEOUT") || i === tries) throw e;
await new Promise((r) => setTimeout(r, 100 * 2 ** i));
}
}
}
const rows = await withRetry(() => db.all("SELECT ...")); Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- retryFetch: attempts must be a finite integer >= 1, got ${at
- remoteWritesExperimental requires a non-null URL
- sync is disabled as database was opened without sync support
- overwriting the 'Host' header is not supported
- HTTP error! status: ${response.status}
AI-assisted analysis of tursodatabase/turso@bad083fafb (2026-08-16).
Data as JSON: /api/errors/f6d33dad7461fa10.
Report an issue: GitHub.