{"record":{"id":"8aac789d55bc4a0d","repo":"benbjohnson/litestream","slug":"shutdown-sync-timeout-after-d-attempts-w","errorCode":null,"errorMessage":"shutdown sync timeout after %d attempts: %w","messagePattern":"shutdown sync timeout after (.+?) attempts: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"db.go","lineNumber":960,"sourceCode":"\t\tif err := db.Replica.Sync(syncCtx); err == nil {\n\t\t\tif attempt > 1 {\n\t\t\t\tdb.Logger.Info(\"shutdown sync succeeded after retry\",\n\t\t\t\t\t\"attempts\", attempt,\n\t\t\t\t\t\"duration\", time.Since(startTime))\n\t\t\t}\n\t\t\treturn nil\n\t\t} else {\n\t\t\tlastErr = err\n\t\t}\n\n\t\t// Check if we should stop retrying (done signal or timeout)\n\t\tselect {\n\t\tcase <-deadlineCtx.Done():\n\t\t\tdb.Logger.Error(\"shutdown sync failed after timeout\",\n\t\t\t\t\"attempts\", attempt,\n\t\t\t\t\"duration\", time.Since(startTime),\n\t\t\t\t\"error\", lastErr)\n\t\t\treturn fmt.Errorf(\"shutdown sync timeout after %d attempts: %w\", attempt, lastErr)\n\t\tcase <-db.Done:\n\t\t\tdb.Logger.Warn(\"shutdown sync interrupted by signal\",\n\t\t\t\t\"attempts\", attempt,\n\t\t\t\t\"duration\", time.Since(startTime),\n\t\t\t\t\"error\", lastErr)\n\t\t\treturn fmt.Errorf(\"after %d attempts: %w\", attempt, ErrShutdownInterrupted)\n\t\tdefault:\n\t\t}\n\n\t\t// Log retry with hint about second signal if interruptible\n\t\tif db.Done != nil {\n\t\t\tdb.Logger.Warn(\"shutdown sync failed, retrying (press Ctrl+C again to skip)\",\n\t\t\t\t\"attempts\", attempt,\n\t\t\t\t\"error\", lastErr,\n\t\t\t\t\"elapsed\", time.Since(startTime),\n\t\t\t\t\"remaining\", time.Until(startTime.Add(timeout)))\n\t\t} else {\n\t\t\tdb.Logger.Warn(\"shutdown sync failed, retrying\",","sourceCodeStart":942,"sourceCodeEnd":978,"githubUrl":"https://github.com/benbjohnson/litestream/blob/4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3/db.go#L942-L978","documentation":"syncReplicaWithRetry retries the final replication on DB.Close until a deadline context expires; when deadlineCtx.Done() fires it returns \"shutdown sync timeout after N attempts\" wrapping the last replication error. This means the final sync could not complete within the configured shutdown timeout despite N retries, and the last underlying error is preserved.","triggerScenarios":"Replica client calls (e.g. S3 uploads) keep failing or hanging — network partition, throttling, wrong credentials — until the shutdown deadline elapses during db.Close().","commonSituations":"S3 endpoint unreachable or credentials expired at shutdown; very large pending LTX uploads on a slow link exceeding the timeout; storage provider returning 5xx/403 repeatedly.","solutions":["Inspect the wrapped lastErr (%w) for the true cause (auth, DNS, throttling) and fix the storage backend issue.","Increase the shutdown sync timeout so large uploads can complete.","Use errors.Is for known sentinel causes and retry the shutdown later; the data is still durable locally in the WAL/LTX files."],"exampleFix":"// before\nif err := store.Close(); err != nil { log.Fatal(err) }\n// after\nif err := store.Close(); err != nil {\n    var terr *litestream.ShutdownTimeoutError // or match on prefix/wrapped cause\n    log.Printf(\"shutdown sync incomplete: %v\", err) // inspect %w cause: S3 403, timeout, etc.\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := db.Close(); err != nil {\n    if strings.Contains(err.Error(), \"shutdown sync timeout\") {\n        log.Printf(\"final sync timed out, cause: %v\", errors.Unwrap(errors.Unwrap(err)))\n    }\n    return err\n}","preventionTips":["Increase shutdown timeout to cover large WAL uploads.","Verify storage credentials and endpoint health before shutdown windows.","Alert on replication errors so the final sync starts from a healthy state."],"tags":["shutdown","timeout","replication","retry","network"],"backgroundTag":"request-timeout","analyzedSha":"4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3","analyzedAt":"2026-09-06T18:29:25.564Z","contentChangedAt":"2026-09-06T18:29:25.564Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}