{"record":{"id":"34b41445b13f388f","repo":"benbjohnson/litestream","slug":"oss-delete-batch-of-d-objects-w","errorCode":null,"errorMessage":"oss: delete batch of %d objects: %w","messagePattern":"oss: delete batch of (.+?) objects: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"oss/replica_client.go","lineNumber":322,"sourceCode":"\t\tkey := c.ltxPath(info.Level, filename)\n\t\tobjects = append(objects, oss.DeleteObject{Key: oss.Ptr(key)})\n\n\t\tc.logger.Debug(\"deleting ltx file\", \"level\", info.Level, \"minTXID\", info.MinTXID, \"maxTXID\", info.MaxTXID, \"key\", key)\n\t}\n\n\t// Delete in batches\n\tfor len(objects) > 0 {\n\t\tn := min(len(objects), MaxKeys)\n\t\tbatch := objects[:n]\n\n\t\trequest := &oss.DeleteMultipleObjectsRequest{\n\t\t\tBucket:  oss.Ptr(c.Bucket),\n\t\t\tObjects: batch,\n\t\t}\n\n\t\tout, err := c.client.DeleteMultipleObjects(ctx, request)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"oss: delete batch of %d objects: %w\", n, err)\n\t\t} else if err := deleteResultError(batch, out); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tinternal.OperationTotalCounterVec.WithLabelValues(ReplicaClientType, \"DELETE\").Inc()\n\n\t\tobjects = objects[n:]\n\t}\n\n\treturn nil\n}\n\n// DeleteAll deletes all files.\nfunc (c *ReplicaClient) DeleteAll(ctx context.Context) error {\n\tif err := c.Init(ctx); err != nil {\n\t\treturn err\n\t}\n","sourceCodeStart":304,"sourceCodeEnd":340,"githubUrl":"https://github.com/benbjohnson/litestream/blob/4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3/oss/replica_client.go#L304-L340","documentation":"DeleteAll-style cleanup lists and then deletes objects in batches; DeleteMultipleObjects failed at the transport/API level for a batch of n objects. The error includes the batch size for debugging. Per-object deletion errors are handled separately via deleteResultError.","triggerScenarios":"Retenion/compaction cleanup calling DeleteLTXFiles when OSS returns an API-level error: AccessDenied on oss:DeleteObjects, NoSuchBucket, rate limiting, or network interruption.","commonSituations":"RAM policy grants Put/Get but not DeleteObjects; bucket under WORM/retention lock preventing deletes; throttling during mass retention cleanup of many LTX files.","solutions":["Grant the RAM role oss:DeleteObjects (and oss:DeleteObject) permission on the bucket/path.","Check the wrapped OSS error code: throttling (SlowDown) means reduce retention churn or retry later.","Verify the bucket still exists and the endpoint/region are correct.","If a retention lock (compliance mode) blocks deletion, remove the lock or exclude this bucket from retention."],"exampleFix":"// before (RAM policy)\n{\"Effect\":\"Allow\",\"Action\":[\"oss:PutObject\",\"oss:GetObject\"],\"Resource\":\"acs:oss:*:*:my-bucket/*\"}\n// after\n{\"Effect\":\"Allow\",\"Action\":[\"oss:PutObject\",\"oss:GetObject\",\"oss:DeleteObject\",\"oss:DeleteObjects\"],\"Resource\":\"acs:oss:*:*:my-bucket/*\"}","handlingStrategy":"retry","validationCode":"// Pre-check permission surface with a dry-run listing before enabling retention cleanup.\nif _, err := client.ListLTXFiles(ctx); err != nil { return err }","typeGuard":null,"tryCatchPattern":"err := client.DeleteLTXFiles(ctx, keys)\nif err != nil {\n    if strings.Contains(err.Error(), \"SlowDown\") { time.Sleep(backoff); return retry() }\n    return fmt.Errorf(\"delete ltx: %w\", err)\n}","preventionTips":["Include oss:DeleteObject/oss:DeleteObjects in the RAM policy from day one.","Avoid retention-locked (WORM) buckets for litestream replicas.","Stagger retention cleanup windows to dodge throttling."],"tags":["oss","delete","permissions","storage"],"backgroundTag":"permission-denied","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"}