flipped-aurora/gin-vue-admin · error

function client.Object.Head() failed, err:

Error message

function client.Object.Head() failed, err:

What it means

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.

Source

Thrown at server/utils/upload/tencent_cos.go:61

	_, err := client.Object.Delete(context.Background(), name)
	if err != nil {
		logger.WithCtx(ctx).Mod("upload").Err(err).Error("function bucketManager.Delete() failed")
		return errors.New("function bucketManager.Delete() failed, err:" + err.Error())
	}
	return nil
}

// Exists 通过 Object.Head 检查对象是否存在;404 统一降级为 (false, nil)。
func (*TencentCOS) Exists(ctx context.Context, key string) (bool, error) {
	client := NewClient()
	name := global.GVA_CONFIG.TencentCOS.PathPrefix + "/" + key
	_, err := client.Object.Head(ctx, name, nil)
	if err != nil {
		if cos.IsNotFoundError(err) {
			return false, nil
		}
		logger.WithCtx(ctx).Mod("upload").Err(err).Error("function client.Object.Head() failed")
		return false, errors.New("function client.Object.Head() failed, err:" + err.Error())
	}
	return true, nil
}

// DeleteFiles 批量删除:Object.DeleteMulti 一次提交,返回 Errors 逐个失败项。
// PathPrefix 拼接方式与 DeleteFile 一致。
func (*TencentCOS) DeleteFiles(ctx context.Context, keys []string) (failed []DeleteFailure, err error) {
	client := NewClient()
	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 {

View on GitHub (pinned to 3136500ef3)

Solutions

  1. Check the wrapped err suffix for the COS error code
  2. Ensure CAM grants cos:HeadObject/GetObject for the key
  3. Verify Bucket and Region config so the correct endpoint is used
  4. If you expect 404, note it is already handled — only non-404 failures reach this error

Example fix

// before
ok, err := cos.Exists(ctx, key) // 403 AccessDenied surfaces as wrapped Head error
// after
if err != nil && strings.Contains(err.Error(), "AccessDenied") {
    return fmt.Errorf("check CAM permissions for cos:HeadObject: %w", err)
}
Defensive patterns

Strategy: try-catch

Validate before calling

cfg := global.GVA_CONFIG.TencentCOS
if cfg.Bucket == "" || cfg.Region == "" {
    return errors.New("cos bucket/region not configured")
}

Try / catch

ok, err := cos.Exists(ctx, key)
if err != nil {
    // 404 already mapped to (false, nil); here it's auth/network/permission
    if strings.Contains(err.Error(), "AccessDenied") {
        // fix CAM cos:HeadObject permission
    }
    return false, err
}

Prevention

When it happens

Trigger: Calling Exists(ctx, key) when Object.Head fails for reasons other than not-found: auth failure, permission denied, network error, or malformed key.

Common situations: Invalid/expired Tencent COS credentials, CAM policy missing cos:GetObject/HeadObject, bucket region mismatch causing endpoint errors, VPC networking issues.

Related errors


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