{"record":{"id":"89e1266b8c9b5162","repo":"flipped-aurora/gin-vue-admin","slug":"function-client-deleteobject-failed-err","errorCode":null,"errorMessage":"function client.DeleteObject() failed, err:","messagePattern":"function client\\.DeleteObject\\(\\) failed, err:","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/utils/upload/aws_s3.go","lineNumber":82,"sourceCode":"//@description: Delete file from Aws S3 using aws-sdk-go-v2. See https://docs.aws.amazon.com/sdk-for-go/v2/developer-guide/s3-example-basic-bucket-operations.html\n//@param: key string\n//@return: error\n\nfunc (*AwsS3) DeleteFile(ctx context.Context, key string) error {\n\tclient, err := newS3Client()\n\tif err != nil {\n\t\treturn err\n\t}\n\tfilename := global.GVA_CONFIG.AwsS3.PathPrefix + \"/\" + key\n\tbucket := global.GVA_CONFIG.AwsS3.Bucket\n\n\t_, err = client.DeleteObject(context.TODO(), &s3.DeleteObjectInput{\n\t\tBucket: aws.String(bucket),\n\t\tKey:    aws.String(filename),\n\t})\n\tif err != nil {\n\t\tlogger.WithCtx(ctx).Mod(\"upload\").Err(err).Error(\"function client.DeleteObject() failed\")\n\t\treturn errors.New(\"function client.DeleteObject() failed, err:\" + err.Error())\n\t}\n\n\twaiter := s3.NewObjectNotExistsWaiter(client)\n\t_ = waiter.Wait(context.TODO(), &s3.HeadObjectInput{\n\t\tBucket: aws.String(bucket),\n\t\tKey:    aws.String(filename),\n\t}, 30*time.Second)\n\n\treturn nil\n}\n\n// Exists 检查对象是否存在。404 统一降级为 (false, nil)。\nfunc (*AwsS3) Exists(ctx context.Context, key string) (bool, error) {\n\tclient, err := newS3Client()\n\tif err != nil {\n\t\treturn false, err\n\t}\n\tbucket := global.GVA_CONFIG.AwsS3.Bucket","sourceCodeStart":64,"sourceCodeEnd":100,"githubUrl":"https://github.com/flipped-aurora/gin-vue-admin/blob/3136500ef380842b0eb6c4daa87c3f8a47fcf9e0/server/utils/upload/aws_s3.go#L64-L100","documentation":"Wraps the error from the AWS SDK v2 client.DeleteObject() call in AwsS3.DeleteFile. The SDK returns an error when the delete request fails at the API level: invalid credentials, missing s3:DeleteObject permission, wrong bucket/key, or network/API failure. This is the first half of DeleteFile; afterwards the code waits for ObjectNotExists to confirm deletion, but this error fires before that wait.","triggerScenarios":"Calling DeleteFile when: the IAM identity lacks s3:DeleteObject on the key, the bucket name resolved from config/bucket parameter is wrong, credentials are invalid, the key contains characters that were improperly encoded, or a network error/timeout occurs against the S3 endpoint.","commonSituations":"Read-only IAM policies applied to the app role; bucket misspelled or pointing at another environment; S3-compatible endpoints (MinIO) unreachable; object key built with an untrimmed path prefix so the key never matches.","solutions":["Grant s3:DeleteObject (and s3:ListBucket for existence checks) to the credentials used by the SDK","Log/inspect the appended err detail: AccessDenied => fix policy, NoSuchBucket => fix bucket name, networking => check endpoint/region","Verify the key passed to DeleteObject matches the stored key exactly (no leading slash, correct PathPrefix)","Test the same delete with aws s3api delete-object using identical credentials to isolate app vs AWS config"],"exampleFix":"// before\nKey: aws.String(\"/\" + filename) // leading slash creates a mismatched key\n// after\nKey: aws.String(strings.TrimPrefix(filename, \"/\"))","handlingStrategy":"try-catch","validationCode":"key := strings.TrimPrefix(filename, \"/\")\nif bucket == \"\" || key == \"\" {\n    return errors.New(\"delete requires non-empty bucket and key\")\n}\n_, err := client.HeadObject(ctx, &s3.HeadObjectInput{Bucket: aws.String(bucket), Key: aws.String(key)})\nif err != nil { return fmt.Errorf(\"object %s not found/accessible before delete: %w\", key, err) }","typeGuard":"func isAccessDenied(err error) bool {\n    var ae smithy.APIError\n    return errors.As(err, &ae) && (ae.ErrorCode() == \"AccessDenied\" || ae.ErrorCode() == \"NoSuchBucket\")\n}","tryCatchPattern":"err := s3Store.DeleteFile(key)\nvar ae smithy.APIError\nif err != nil && errors.As(err, &ae) {\n    switch ae.ErrorCode() {\n    case \"AccessDenied\": return fmt.Errorf(\"missing s3:DeleteObject on %s: %w\", key, err)\n    case \"NoSuchBucket\": return fmt.Errorf(\"check bucket config: %w\", err)\n    default: return err\n    }\n}","preventionTips":["Verify key construction (PathPrefix + timestamp + filename) matches keys produced by UploadFile","Include s3:DeleteObject and s3:ListBucket in the runtime IAM policy","Use aws s3api delete-object with the same credentials as a smoke test during setup","Log the raw SDK error code, not just the wrapped message, for faster triage"],"tags":["aws-s3","aws-sdk-go-v2","delete-object","permissions"],"backgroundTag":"s3-access-denied","analyzedSha":"3136500ef380842b0eb6c4daa87c3f8a47fcf9e0","analyzedAt":"2026-08-31T13:50:02.721Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}