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

  1. Cap each DeleteFiles batch at 1000 keys and chunk larger lists before calling
  2. Inspect the wrapped err text: AccessDenied -> token permissions; MalformedXML/oversized -> batch too large; timeout -> network
  3. Check keys for path-join artifacts (empty strings, double slashes) and sanitize before deleting
  4. Verify endpoint/bucket config as in the single DeleteFile case
  5. 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

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


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