{"record":{"id":"77d938639ddf32c8","repo":"benbjohnson/litestream","slug":"s3-put-object-s-w","errorCode":null,"errorMessage":"s3: put object %s: %w","messagePattern":"s3: put object (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"s3/replica_client.go","lineNumber":804,"sourceCode":"\t// Extract timestamp from LTX header, then rewind so the upload sees the\n\t// full file.\n\thdr, _, err := ltx.PeekHeader(rs)\n\tif err != nil {\n\t\treturn 0, time.Time{}, nil, fmt.Errorf(\"extract timestamp from LTX header: %w\", err)\n\t}\n\ttimestamp := time.UnixMilli(hdr.Timestamp).UTC()\n\tif _, err := rs.Seek(start, io.SeekStart); err != nil {\n\t\treturn 0, time.Time{}, nil, fmt.Errorf(\"s3: rewind ltx file %s: %w\", key, err)\n\t}\n\n\tinput := c.putObjectInput(key, timestamp)\n\tinput.Body = rs\n\n\tif size < partSize {\n\t\tinput.ContentLength = aws.Int64(size)\n\t\tout, err := c.s3.PutObject(ctx, input)\n\t\tif err != nil {\n\t\t\treturn 0, time.Time{}, nil, fmt.Errorf(\"s3: put object %s: %w\", key, err)\n\t\t}\n\t\treturn size, timestamp, out.ETag, nil\n\t}\n\n\t// At or above the part size the uploader splits the seekable body into\n\t// section readers without copying it into part buffers.\n\tout, err := c.uploader.Upload(ctx, input)\n\tif err != nil {\n\t\treturn 0, time.Time{}, nil, fmt.Errorf(\"s3: upload to %s: %w\", key, err)\n\t}\n\treturn size, timestamp, out.ETag, nil\n}\n\n// uploadStreamedLTX uploads from a reader of unknown size, buffering up to\n// the part size to determine whether the object fits in a single PutObject.\nfunc (c *ReplicaClient) uploadStreamedLTX(ctx context.Context, key string, r io.Reader, partSize int64) (int64, time.Time, *string, error) {\n\t// Use TeeReader to peek at LTX header while preserving data for upload\n\tvar buf bytes.Buffer","sourceCodeStart":786,"sourceCodeEnd":822,"githubUrl":"https://github.com/benbjohnson/litestream/blob/4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3/s3/replica_client.go#L786-L822","documentation":"The single-put path (files smaller than partSize) calls the S3 PutObject API; any API-level failure is wrapped in this error. Causes include network failures, expired/invalid credentials, missing bucket, permissions, or S3 5xx errors. The returned error preserves the AWS SDK error for inspection via errors.As/unwrap.","triggerScenarios":"PutObject returns an SDK error: connectivity loss, invalid AWS credentials, bucket does not exist or is in another region, IAM policy denies s3:PutObject, bucket policy/Object Lock rejects the write, or S3 throttling/slow-down responses.","commonSituations":"Rotated IAM keys not updated in the environment; region mismatch between client config and bucket; private-link/VPC endpoint misconfiguration; S3 outage or rate limiting during large replication bursts.","solutions":["Unwrap the error (errors.As to smithy OperationError / awshttp.ResponseError) to see the HTTP status and S3 error code","Verify credentials (aws sts get-caller-identity) and that s3:PutObject is allowed for the bucket/key prefix","Confirm the bucket exists in the configured region and the region setting matches","Check network path: DNS, proxy, VPC endpoint, and retry with backoff for transient 5xx/throttling"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// preflight before uploads\nif _, err := c.s3.HeadBucket(ctx, &s3.HeadBucketInput{Bucket: bucket}); err != nil {\n    return fmt.Errorf(\"bucket unreachable: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"var opErr *smithy.OperationError\nif errors.As(err, &opErr) {\n    var respErr *awshttp.ResponseError\n    if errors.As(opErr.Err, &respErr) {\n        // inspect respErr.HTTPStatusCode(): retry on 5xx/429, fix creds/perms on 4xx\n    }\n}","preventionTips":["Rotate AWS credentials before expiry and verify with sts get-caller-identity","Match client region to bucket region","Grant s3:PutObject on the exact bucket/prefix in IAM","Add exponential backoff for throttling and 5xx errors"],"tags":["s3","network","aws","upload"],"backgroundTag":"api-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"}