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

  1. Inspect code= and message= on each DeleteFailure to identify the COS error and affected key.
  2. Grant the secret's CAM role cos:DeleteObject permission on the bucket.
  3. Normalize key names (strip leading '/', validate characters) before batch delete.
  4. 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

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


AI-assisted analysis of flipped-aurora/gin-vue-admin@3136500ef3 (2026-08-31). Data as JSON: /api/errors/79106b056a12eb9d. Report an issue: GitHub.