{"record":{"id":"e873bee7772ed6dc","repo":"benbjohnson/litestream","slug":"upload-ltx-w","errorCode":null,"errorMessage":"upload LTX: %w","messagePattern":"upload LTX: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"vfs.go","lineNumber":2012,"sourceCode":"\t// Double-check dirty pages exist\n\tif len(f.dirty) == 0 {\n\t\treturn nil\n\t}\n\n\tctx := f.ctx\n\n\t// Check for conflicts\n\tif err := f.checkForConflict(ctx); err != nil {\n\t\treturn err\n\t}\n\n\t// Create LTX file from dirty pages\n\tltxReader := f.createLTXFromDirty()\n\n\t// Upload LTX file to remote\n\tinfo, err := f.client.WriteLTXFile(ctx, 0, f.pendingTXID, f.pendingTXID, ltxReader)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"upload LTX: %w\", err)\n\t}\n\n\tf.logger.Info(\"synced to remote\",\n\t\t\"txid\", info.MaxTXID,\n\t\t\"pages\", len(f.dirty),\n\t\t\"size\", info.Size)\n\n\tf.expectedTXID = f.pendingTXID\n\tf.pendingTXID++\n\tf.pos = ltx.Pos{TXID: f.expectedTXID}\n\n\tif f.vfs != nil {\n\t\tf.vfs.writeMu.Lock()\n\t\tif f.expectedTXID > f.vfs.lastSyncedTXID {\n\t\t\tf.vfs.lastSyncedTXID = f.expectedTXID\n\t\t}\n\t\tf.vfs.writeMu.Unlock()\n\t}","sourceCodeStart":1994,"sourceCodeEnd":2030,"githubUrl":"https://github.com/benbjohnson/litestream/blob/4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3/vfs.go#L1994-L2030","documentation":"syncToRemoteWithLock built an LTX file from the dirty pages and failed to upload it to the replica via client.WriteLTXFile. The dirty pages remain dirty and pendingTXID is not advanced, so no data was committed remotely; the wrapped error is the storage client's failure (network, credentials, permissions, conflict).","triggerScenarios":"Sync() during transactions-off periods, periodic syncLoop tick, or the final sync in SetWriteEnabled(false), whenever the replica client cannot write the LTX file: network outage, expired AWS/S3 credentials, bucket permissions, or a TXID conflict detected just before upload.","commonSituations":"S3/Cloudflare R2 outages or throttling; IAM policy revoking PutObject on the bucket; rotating credentials without restarting litestream; concurrent writer from another node advancing remote TXID (competing writers without leasing); firewall blocking egress to the storage endpoint.","solutions":["Check the wrapped cause: fix network egress, refresh credentials, or correct bucket IAM permissions.","If it's a TXID conflict, ensure only one writer replicates per database (use leasing) or litestream reset local state and re-enable.","Retry after transient failures — dirty state is preserved and the next sync tick will retry automatically.","Verify replica client config (endpoint, region, bucket) with litestream ltx listing against the same bucket.","Increase storage request timeouts / check rate limits if errors are throttling responses."],"exampleFix":"// before\nclient := s3.NewReplicaClient() // uses expired env credentials\n// after\nclient = s3.NewReplicaClient()\nclient.AccessKeyID, client.SecretAccessKey = refreshedKeys() // rotate before sync","handlingStrategy":"retry","validationCode":"// Go: pre-flight replica write check before enabling write support\nctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)\ndefer cancel()\nitr, err := client.LTXFiles(ctx, 0, 0, false)\nif err != nil { return fmt.Errorf(\"replica not reachable: %w\", err) }\nitr.Close()","typeGuard":null,"tryCatchPattern":"if err := file.Sync(); err != nil {\n    if strings.HasPrefix(err.Error(), \"upload LTX:\") {\n        if errors.Is(err, context.DeadlineExceeded) || isTransient(err) {\n            time.Sleep(backoff) // dirty pages preserved; next tick retries\n        }\n    }\n}","preventionTips":["Monitor credential expiry and rotate without downtime.","Enforce single-writer (leasing) to prevent TXID conflicts.","Alert on periodic syncLoop 'periodic sync failed' log lines.","Verify bucket IAM allows PutObject and check egress firewall rules."],"tags":["go","replication","upload","s3","network","ltx"],"backgroundTag":"http-request-failed","analyzedSha":"4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3","analyzedAt":"2026-09-06T18:29:25.564Z","contentChangedAt":"2026-09-06T18:29:25.564Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}