flipped-aurora/gin-vue-admin · error
cos delete %s failed: code=%s, message=%s
Error message
cos delete %s failed: code=%s, message=%s
What it means
The Tencent COS DeleteFiles implementation issues a multi-delete and inspects res.Errors for per-object failures, wrapping each as "cos delete %s failed: code=%s, message=%s" with the COS error code and message. The overall request can succeed while individual key deletions fail, and this surfaces those partial failures.
Source
Thrown at server/utils/upload/tencent_cos.go:88
objects := make([]cos.Object, 0, len(keys))
for _, k := range keys {
objects = append(objects, cos.Object{Key: global.GVA_CONFIG.TencentCOS.PathPrefix + "/" + k})
}
res, _, err := client.Object.DeleteMulti(ctx, &cos.ObjectDeleteMultiOptions{
Objects: objects,
Quiet: true,
})
if err != nil {
logger.WithCtx(ctx).Mod("upload").Err(err).Error("function client.Object.DeleteMulti() failed")
return nil, errors.New("function client.Object.DeleteMulti() failed, err:" + err.Error())
}
if res != nil {
for _, e := range res.Errors {
failed = append(failed, DeleteFailure{
Key: e.Key,
Err: fmt.Errorf("cos delete %s failed: code=%s, message=%s", e.Key, e.Code, e.Message),
})
}
}
return failed, nil
}
// ListFiles 按前缀列举对象,marker 分页:Marker=cursor,NextMarker→nextCursor,IsTruncated→hasMore。
func (*TencentCOS) ListFiles(ctx context.Context, prefix, cursor string, limit int) (files []FileInfo, nextCursor string, hasMore bool, err error) {
if limit <= 0 {
limit = 100
}
client := NewClient()
res, _, err := client.Bucket.Get(ctx, &cos.BucketGetOptions{
Prefix: prefix,
Marker: cursor,
MaxKeys: limit,
})View on GitHub (pinned to 3136500ef3)
Solutions
- Inspect code= and message= on each DeleteFailure to identify the COS error and affected key.
- Grant the secret's CAM role cos:DeleteObject permission on the bucket.
- Normalize key names (strip leading '/', validate characters) before batch delete.
- Retry only failed keys; treat AlreadyDeleted responses as success if idempotency is needed.
Example fix
// before
failed, _ := uploader.DeleteFiles(ctx, keys)
// after
failed, err := uploader.DeleteFiles(ctx, keys)
for _, f := range failed {
log.Printf("cos delete retry for %s: %v", f.Key, f.Err)
} Defensive patterns
Strategy: try-catch
Validate before calling
for _, key := range keys {
if strings.HasPrefix(key, "/") {
return fmt.Errorf("COS keys must not start with '/': %q", key)
}
} Try / catch
failed, err := uploader.DeleteFiles(ctx, keys)
if err != nil {
return err
}
for _, f := range failed {
log.Printf("cos delete failed key=%s: %v", f.Key, f.Err)
// parse code= to distinguish AccessDenied vs NoSuchKey
} Prevention
- Ensure the CAM role has cos:DeleteObject on the bucket
- Normalize keys (trim leading slashes) before batch delete
- Always inspect the failed list — COS batch delete is partial-capable
- Enable bucket audit logs to trace denied deletes
When it happens
Trigger: Calling DeleteFiles on the tencent_cos uploader when res.Errors is non-empty — e.g. AccessDenied on a key, keys that no longer exist, or invalid key names rejected by COS.
Common situations: CAM policy lacking cos:DeleteObject for the bucket; objects already deleted by lifecycle rules; malformed keys (leading slash, invalid characters) in the batch request.
Related errors
- function bucketManager.Delete() failed, err:
- function bucketManager.Delete() failed, err:
- obs delete %s failed: code=%s, message=%s
- delete failed, code: %d
- function client.DeleteObject() failed, err:
AI-assisted analysis of flipped-aurora/gin-vue-admin@3136500ef3 (2026-08-31).
Data as JSON: /api/errors/79106b056a12eb9d.
Report an issue: GitHub.