{"record":{"id":"28e474b5a2384a57","repo":"rqlite/rqlite","slug":"queue-wait-timeout","errorCode":null,"errorMessage":"queue wait timeout","messagePattern":"queue wait timeout","errorType":"http","errorClass":null,"httpStatus":408,"severity":"error","filePath":"http/service.go","lineNumber":1325,"sourceCode":"\t\tstats.Add(numQueuedExecutionsWait, 1)\n\t\tfc = make(queue.FlushChannel)\n\t}\n\n\tseqNum, err := s.stmtQueue.Write(stmts, fc)\n\tif err != nil {\n\t\thttp.Error(w, err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\tresp.SequenceNum = seqNum\n\n\tif qp.Wait() {\n\t\t// Wait for the flush channel to close, or timeout.\n\t\tselect {\n\t\tcase <-fc:\n\t\t\tbreak\n\t\tcase <-time.NewTimer(qp.Timeout(defaultTimeout)).C:\n\t\t\tstats.Add(numQueuedExecutionsWaitTimeout, 1)\n\t\t\thttp.Error(w, \"queue wait timeout\", http.StatusRequestTimeout)\n\t\t\treturn\n\t\t}\n\t}\n\n\tresp.end = time.Now()\n\ts.writeResponse(w, qp, resp)\n}\n\n// execute handles queries that modify the database.\nfunc (s *Service) execute(w http.ResponseWriter, r *http.Request, qp QueryParams) {\n\tresp := NewResponse()\n\tresp.Results.AssociativeJSON = qp.Associative()\n\tresp.Results.BlobsAsArrays = qp.BlobArray()\n\n\tvar stmts []*proto.Statement\n\tvar err error\n\tif strings.HasPrefix(r.Header.Get(\"Content-Type\"), \"text/plain\") {\n\t\tsql, err := io.ReadAll(r.Body)","sourceCodeStart":1307,"sourceCodeEnd":1343,"githubUrl":"https://github.com/rqlite/rqlite/blob/7586a4d1bdbd9a5a80021664c5a863cd850adb60/http/service.go#L1307-L1343","documentation":"rqlite returns HTTP 408 'queue wait timeout' when a write submitted to the queued-write pipeline (?queue) waited longer than the client's configured timeout for its statements to be flushed to the Raft log. The server accepted the request into the queue, but the flusher did not pick it up before qp.Timeout(defaultTimeout) elapsed, so the wait on the flush channel aborted and the request is failed without any guarantee the write was applied.","triggerScenarios":"POST /db/execute?queue=now (or via CLI queued writes) while the queued-writer's batch flush interval is large, the queue is backed up, or the supplied 'timeout' query parameter is shorter than the queue flush latency; the select in execute() at http/service.go:1325 times out waiting on the flush channel.","commonSituations":"High write throughput overwhelming the queue batcher; setting timeout=1 on queued writes while the default flush interval is longer; leader under heavy Raft fsync latency on slow disks; large batches from bulk writes delaying the flusher.","solutions":["Increase the 'timeout' query parameter on the queued request so it exceeds the queue flush interval and expected flush latency","Reduce write pressure or batch size, or add replicas/read-only nodes and shard writes so the queued writer keeps up","Check leader health and disk I/O (Raft fsync is the bottleneck); move rqlited to faster storage","If immediate durability feedback is needed, drop ?queue and use standard (consensus-waiting) writes"],"exampleFix":"// before\ncurl -XPOST 'localhost:4001/db/execute?queue&timeout=1' -d '[\"INSERT INTO t VALUES(1)\"]'\n// after\ncurl -XPOST 'localhost:4001/db/execute?queue&timeout=10' -d '[\"INSERT INTO t VALUES(1)\"]'","handlingStrategy":"retry","validationCode":"const timeoutMs = 10000; // ensure timeout param > queue flush interval\nconst url = `http://localhost:4001/db/execute?queue&timeout=${timeoutMs/1000}`;\nif (timeoutMs <= 1000) throw new Error('queued-write timeout too small');","typeGuard":"function isQueueWaitTimeout(resp) {\n  return resp.status === 408 && resp.headers.get('Content-Type')?.includes('text/plain') === false;\n}","tryCatchPattern":"const res = await fetch(url, {method:'POST', body});\nif (res.status === 408) {\n  // write MAY still have been applied — treat as indeterminate, check before retrying\n  const check = await fetch('http://localhost:4001/db/query', {method:'POST', body: verifySql});\n  if (!check.ok) await retryWithBackoff(() => postWrite(url, body));\n}","preventionTips":["Set the timeout query parameter well above the queue flush interval","Monitor numQueuedExecutionsWaitTimeout in /status metrics","Keep queued-write rate within the batcher's throughput; shard or batch client-side","Avoid mixing tiny timeouts with bulk writes; use standard (non-queued) writes when durability confirmation matters"],"tags":["http","queueing","timeout","rqlite"],"backgroundTag":"queue-wait-timeout","analyzedSha":"7586a4d1bdbd9a5a80021664c5a863cd850adb60","analyzedAt":"2026-09-03T07:03:02.260Z","contentChangedAt":"2026-09-03T07:03:02.260Z","schemaVersion":2},"datasetVersion":"2026-09-10T12:17:11.382Z"}