benbjohnson/litestream · error
oss: upload to %s: %w
Error message
oss: upload to %s: %w
What it means
The OSS uploader's UploadFrom call failed while streaming an LTX object to the bucket. This wraps any SDK/network error from the PUT: auth failures, bucket/region mismatch, size limits, or mid-stream connection drops.
Source
Thrown at oss/replica_client.go:267
// Combine buffered data with rest of reader
rc := internal.NewReadCounter(io.MultiReader(&buf, r))
filename := ltx.FormatFilename(minTXID, maxTXID)
key := c.ltxPath(level, filename)
// Store timestamp in OSS metadata for accurate timestamp retrieval
metadata := map[string]string{
MetadataKeyTimestamp: timestamp.Format(time.RFC3339Nano),
}
// Use uploader for automatic multipart handling (files >5GB)
result, err := c.uploader.UploadFrom(ctx, &oss.PutObjectRequest{
Bucket: oss.Ptr(c.Bucket),
Key: oss.Ptr(key),
Metadata: metadata,
}, rc)
if err != nil {
return nil, fmt.Errorf("oss: upload to %s: %w", key, err)
}
// Build file info from the uploaded file
info := <x.FileInfo{
Level: level,
MinTXID: minTXID,
MaxTXID: maxTXID,
Size: rc.N(),
CreatedAt: timestamp,
}
internal.OperationTotalCounterVec.WithLabelValues(ReplicaClientType, "PUT").Inc()
internal.OperationBytesCounterVec.WithLabelValues(ReplicaClientType, "PUT").Add(float64(rc.N()))
// ETag indicates successful upload
if result.ETag == nil || *result.ETag == "" {
return nil, fmt.Errorf("oss: upload failed: no ETag returned")
}View on GitHub (pinned to 4ed7a308f6)
Solutions
- Read the wrapped OSS error code: fix AccessDenied by granting oss:PutObject; fix NoSuchBucket by creating the bucket.
- Verify region/endpoint matches the bucket (set region explicitly in config instead of relying on the cn-hangzhou default).
- Rotate/refresh credentials if the error indicates signature or token expiration (STS tokens expire).
- Check network stability/proxy config; Litestream will retry the upload on the next sync.
Example fix
// before
replicas:
- type: oss
bucket: my-bucket
path: ltx
// after
replicas:
- type: oss
bucket: my-bucket
region: oss-cn-beijing
endpoint: https://oss-cn-beijing.aliyuncs.com
path: ltx Defensive patterns
Strategy: retry
Validate before calling
if err := client.Init(ctx); err != nil { return err } // fails fast on bad config/creds
if _, err := client.HeadBucket(ctx); err != nil { return err } Try / catch
_, err := client.WriteLTXFile(ctx, key, metadata, r, size)
if err != nil {
var netErr net.Error
if errors.As(err, &netErr) || isRetryable(err) {
time.Sleep(backoff); return retry()
}
return fmt.Errorf("upload ltx: %w", err)
} Prevention
- Use long-lived RAM roles or refresh STS tokens before expiry.
- Set explicit region/endpoint matching the bucket.
- Ensure stable network for the replication host; uploads of large compaction files need sustained bandwidth.
When it happens
Trigger: WriteLTXFile uploading a newly created LTX file when credentials expire, the network drops mid-upload, the bucket does not exist in the target region, or the RAM policy lacks oss:PutObject.
Common situations: Stale AccessKey after rotation; bucket deleted or renamed; regional endpoint misconfigured (defaulting to cn-hangzhou when the bucket lives elsewhere); large compaction files hitting transient timeouts on slow links.
Understand the failure class
Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.
Related errors
- oss: get object %s: %w
- write ltx file: %w
- abs: cannot delete ltx file %q: %w
- abs: cannot list blobs: %w
- abs: cannot delete blob %q: %w
AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06).
Data as JSON: /api/errors/bd0dd3fe406b3709.
Report an issue: GitHub.