{"record":{"id":"a23cd6d49f74fecf","repo":"flipped-aurora/gin-vue-admin","slug":"function-client-object-head-failed-err","errorCode":null,"errorMessage":"function client.Object.Head() failed, err:","messagePattern":"function client\\.Object\\.Head\\(\\) failed, err:","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/utils/upload/tencent_cos.go","lineNumber":61,"sourceCode":"\t_, err := client.Object.Delete(context.Background(), name)\n\tif err != nil {\n\t\tlogger.WithCtx(ctx).Mod(\"upload\").Err(err).Error(\"function bucketManager.Delete() failed\")\n\t\treturn errors.New(\"function bucketManager.Delete() failed, err:\" + err.Error())\n\t}\n\treturn nil\n}\n\n// Exists 通过 Object.Head 检查对象是否存在；404 统一降级为 (false, nil)。\nfunc (*TencentCOS) Exists(ctx context.Context, key string) (bool, error) {\n\tclient := NewClient()\n\tname := global.GVA_CONFIG.TencentCOS.PathPrefix + \"/\" + key\n\t_, err := client.Object.Head(ctx, name, nil)\n\tif err != nil {\n\t\tif cos.IsNotFoundError(err) {\n\t\t\treturn false, nil\n\t\t}\n\t\tlogger.WithCtx(ctx).Mod(\"upload\").Err(err).Error(\"function client.Object.Head() failed\")\n\t\treturn false, errors.New(\"function client.Object.Head() failed, err:\" + err.Error())\n\t}\n\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 {","sourceCodeStart":43,"sourceCodeEnd":79,"githubUrl":"https://github.com/flipped-aurora/gin-vue-admin/blob/3136500ef380842b0eb6c4daa87c3f8a47fcf9e0/server/utils/upload/tencent_cos.go#L43-L79","documentation":"Wraps a non-404 error from the COS SDK's client.Object.Head() in TencentCOS.Exists(). Head fetches object metadata to test existence; cos.IsNotFoundError results are converted to (false, nil), everything else is re-wrapped with this prefix.","triggerScenarios":"Calling Exists(ctx, key) when Object.Head fails for reasons other than not-found: auth failure, permission denied, network error, or malformed key.","commonSituations":"Invalid/expired Tencent COS credentials, CAM policy missing cos:GetObject/HeadObject, bucket region mismatch causing endpoint errors, VPC networking issues.","solutions":["Check the wrapped err suffix for the COS error code","Ensure CAM grants cos:HeadObject/GetObject for the key","Verify Bucket and Region config so the correct endpoint is used","If you expect 404, note it is already handled — only non-404 failures reach this error"],"exampleFix":"// before\nok, err := cos.Exists(ctx, key) // 403 AccessDenied surfaces as wrapped Head error\n// after\nif err != nil && strings.Contains(err.Error(), \"AccessDenied\") {\n    return fmt.Errorf(\"check CAM permissions for cos:HeadObject: %w\", err)\n}","handlingStrategy":"try-catch","validationCode":"cfg := global.GVA_CONFIG.TencentCOS\nif cfg.Bucket == \"\" || cfg.Region == \"\" {\n    return errors.New(\"cos bucket/region not configured\")\n}","typeGuard":null,"tryCatchPattern":"ok, err := cos.Exists(ctx, key)\nif err != nil {\n    // 404 already mapped to (false, nil); here it's auth/network/permission\n    if strings.Contains(err.Error(), \"AccessDenied\") {\n        // fix CAM cos:HeadObject permission\n    }\n    return false, err\n}","preventionTips":["Grant cos:HeadObject/GetObject permissions","Validate bucket/region config at startup","Do not conflate not-found (false,nil) with real failures"],"tags":["tencent-cos","exists","object-storage","permissions"],"backgroundTag":"object-storage-head-failed","analyzedSha":"3136500ef380842b0eb6c4daa87c3f8a47fcf9e0","analyzedAt":"2026-08-31T13:50:02.721Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}