flipped-aurora/gin-vue-admin · error
function client.DeleteObjects() failed, err:
Error message
function client.DeleteObjects() failed, err:
What it means
CloudflareR2.DeleteFiles performs a batch DeleteObjects (multi-object delete); an SDK-level failure of the batch request is wrapped in this message. This is distinct from per-key failures — it means the whole HTTP/API call failed and no batch result was produced.
Source
Thrown at server/utils/upload/cloudflare_r2.go:133
objects := make([]types.ObjectIdentifier, 0, len(keys))
for _, key := range keys {
fullKey := key
// 入参可能是短 key(不含前缀),也可能是 List 出来的全路径 key;统一拼接前缀时避免重复。
if prefix != "" && !strings.HasPrefix(key, prefix+"/") {
fullKey = prefix + "/" + key
}
objects = append(objects, types.ObjectIdentifier{Key: aws.String(fullKey)})
}
out, err := client.DeleteObjects(ctx, &s3.DeleteObjectsInput{
Bucket: aws.String(bucket),
Delete: &types.Delete{
Objects: objects,
Quiet: aws.Bool(true),
},
})
if err != nil {
return nil, errors.New("function client.DeleteObjects() failed, err:" + err.Error())
}
for _, e := range out.Errors {
key := ""
if e.Key != nil {
key = *e.Key
}
msg := "unknown error"
if e.Message != nil {
msg = *e.Message
}
failed = append(failed, DeleteFailure{Key: key, Err: errors.New(msg)})
}
return failed, nil
}
// ListFiles 按前缀列举存储对象,cursor 映射到 ContinuationToken。
func (c *CloudflareR2) ListFiles(ctx context.Context, prefix, cursor string, limit int) (files []FileInfo, nextCursor string, hasMore bool, err error) {View on GitHub (pinned to 3136500ef3)
Solutions
- Cap each DeleteFiles batch at 1000 keys and chunk larger lists before calling
- Inspect the wrapped err text: AccessDenied -> token permissions; MalformedXML/oversized -> batch too large; timeout -> network
- Check keys for path-join artifacts (empty strings, double slashes) and sanitize before deleting
- Verify endpoint/bucket config as in the single DeleteFile case
- Retry the whole batch only after fixing the root cause; batch delete is not safely retryable blindly (though S3 multi-delete is idempotent per key)
Example fix
// before
failed, err := uploader.DeleteFiles(ctx, allKeys) // 5000 keys
// after
for chunk := range slices.Chunk(allKeys, 1000) {
f, err := uploader.DeleteFiles(ctx, chunk)
...
} Defensive patterns
Strategy: validation
Validate before calling
if len(keys) > 1000 {
return errors.New("batch delete limited to 1000 keys per request")
}
for _, k := range keys {
if k == "" || strings.Contains(k, "//") {
return fmt.Errorf("invalid key in batch: %q", k)
}
} Type guard
null
Try / catch
failed, err := uploader.DeleteFiles(ctx, chunk)
if err != nil {
if strings.Contains(err.Error(), "DeleteObjects() failed") {
logger.Error("batch delete transport failure; chunk keys", zap.Strings("keys", chunk), zap.Error(err))
}
return err
}
for _, f := range failed { logger.Warn("key delete failed", zap.String("key", f.Key)) } Prevention
- Chunk batches to <=1000 keys before calling DeleteFiles
- Sanitize keys (trim slashes, reject empties) before batching
- Confirm token write permissions before batch operations
- Log per-key failures from DeleteFailure instead of failing the whole batch
When it happens
Trigger: DeleteFiles(ctx, keys...) when the batch call exceeds request constraints (too many keys), the request payload fails signing/size limits, network to R2 fails, or credentials/permissions are invalid for the delete API.
Common situations: Batch size above limits (S3 caps multi-delete at 1000 keys; oversized payloads via proxies), token without write permission, R2 endpoint unreachable, malformed key names (leading slashes from path joins) causing request rejection.
Related errors
- function client.DeleteObject() failed, err:
- unknown error
- function client.ListObjectsV2() failed, err:
- function bucket.DeleteObjects() failed, err:
- function client.ListObjectsV2() failed, err:
AI-assisted analysis of flipped-aurora/gin-vue-admin@3136500ef3 (2026-08-31).
Data as JSON: /api/errors/7a62ca83c0ac0481.
Report an issue: GitHub.