{"record":{"id":"63437b4a22c9de63","repo":"flipped-aurora/gin-vue-admin","slug":"function-client-object-deletemulti-failed-err","errorCode":null,"errorMessage":"function client.Object.DeleteMulti() failed, err:","messagePattern":"function client\\.Object\\.DeleteMulti\\(\\) failed, err:","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/utils/upload/tencent_cos.go","lineNumber":81,"sourceCode":"\treturn true, nil\n}\n\n// DeleteFiles 批量删除：Object.DeleteMulti 一次提交，返回 Errors 逐个失败项。\n// PathPrefix 拼接方式与 DeleteFile 一致。\nfunc (*TencentCOS) DeleteFiles(ctx context.Context, keys []string) (failed []DeleteFailure, err error) {\n\tclient := NewClient()\n\tobjects := make([]cos.Object, 0, len(keys))\n\tfor _, k := range keys {\n\t\tobjects = append(objects, cos.Object{Key: global.GVA_CONFIG.TencentCOS.PathPrefix + \"/\" + k})\n\t}\n\n\tres, _, err := client.Object.DeleteMulti(ctx, &cos.ObjectDeleteMultiOptions{\n\t\tObjects: objects,\n\t\tQuiet:   true,\n\t})\n\tif err != nil {\n\t\tlogger.WithCtx(ctx).Mod(\"upload\").Err(err).Error(\"function client.Object.DeleteMulti() failed\")\n\t\treturn nil, errors.New(\"function client.Object.DeleteMulti() failed, err:\" + err.Error())\n\t}\n\n\tif res != nil {\n\t\tfor _, e := range res.Errors {\n\t\t\tfailed = append(failed, DeleteFailure{\n\t\t\t\tKey: e.Key,\n\t\t\t\tErr: fmt.Errorf(\"cos delete %s failed: code=%s, message=%s\", e.Key, e.Code, e.Message),\n\t\t\t})\n\t\t}\n\t}\n\treturn failed, nil\n}\n\n// ListFiles 按前缀列举对象，marker 分页：Marker=cursor，NextMarker→nextCursor，IsTruncated→hasMore。\nfunc (*TencentCOS) ListFiles(ctx context.Context, prefix, cursor string, limit int) (files []FileInfo, nextCursor string, hasMore bool, err error) {\n\tif limit <= 0 {\n\t\tlimit = 100\n\t}","sourceCodeStart":63,"sourceCodeEnd":99,"githubUrl":"https://github.com/flipped-aurora/gin-vue-admin/blob/3136500ef380842b0eb6c4daa87c3f8a47fcf9e0/server/utils/upload/tencent_cos.go#L63-L99","documentation":"Wraps a fatal error from the COS SDK's client.Object.DeleteMulti() in TencentCOS.DeleteFiles(). DeleteMulti submits a bulk delete request; a transport-level failure (before the server processes the batch) produces this error. Per-key failures are returned in res.Errors, not here.","triggerScenarios":"Calling DeleteFiles(ctx, keys) when the DeleteMulti request itself fails: auth error, network failure, or request exceeding the batch limit (COS allows up to 1000 objects per call).","commonSituations":"More than 1000 keys in one call, invalid credentials, CAM lacking cos:DeleteObject for the batch, endpoint unreachable.","solutions":["Check the wrapped err suffix for the COS error code","Split key lists into chunks of at most 1000 per DeleteMulti call","Verify credentials and cos:DeleteObject CAM permission","Retry transient network errors; inspect res.Errors for partial per-key failures"],"exampleFix":"// before\ncos.DeleteFiles(ctx, allKeys) // >1000 keys may fail the whole request\n// after\nfor i := 0; i < len(keys); i += 1000 {\n    end := min(i+1000, len(keys))\n    if _, err := cos.DeleteFiles(ctx, keys[i:end]); err != nil {\n        return err\n    }\n}","handlingStrategy":"retry","validationCode":"if len(keys) > 1000 {\n    return fmt.Errorf(\"COS DeleteMulti supports at most 1000 objects, got %d\", len(keys))\n}","typeGuard":null,"tryCatchPattern":"failed, err := cos.DeleteFiles(ctx, keys)\nif err != nil {\n    if isTransientCOS(err) {\n        // retry chunk with backoff\n    }\n    return nil, err\n}\n// inspect `failed` for per-key errors (Quiet=true still returns errors)","preventionTips":["Chunk deletes to <=1000 keys per call","Verify cos:DeleteObject CAM permission","Process per-key DeleteFailure results even on success"],"tags":["tencent-cos","batch-delete","object-storage"],"backgroundTag":"object-storage-batch-delete-failed","analyzedSha":"3136500ef380842b0eb6c4daa87c3f8a47fcf9e0","analyzedAt":"2026-08-31T13:50:02.721Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}