{"record":{"id":"3bd16b4c18ff4920","repo":"kubernetes/kops","slug":"write-to-s-with-acl-of-unexpected-type-t","errorCode":null,"errorMessage":"write to %s with ACL of unexpected type %T","messagePattern":"write to (.+?) with ACL of unexpected type %T","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"util/pkg/vfs/gsfs.go","lineNumber":188,"sourceCode":"\treturn &GSPath{\n\t\tvfsContext: p.vfsContext,\n\t\tbucket:     p.bucket,\n\t\tkey:        joined,\n\t}\n}\n\nfunc (p *GSPath) WriteFile(ctx context.Context, data io.ReadSeeker, acl ACL) error {\n\tmd5Hash, err := hashing.HashAlgorithmMD5.Hash(data)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdone, err := RetryWithBackoff(gcsWriteBackoff, func() (bool, error) {\n\t\tvar objectACL []storage.ACLRule\n\t\tif acl != nil {\n\t\t\tgsACL, ok := acl.(*GSAcl)\n\t\t\tif !ok {\n\t\t\t\treturn true, fmt.Errorf(\"write to %s with ACL of unexpected type %T\", p, acl)\n\t\t\t}\n\t\t\tobjectACL = gsACL.Acl\n\t\t\tklog.V(4).Infof(\"Writing file %q with ACL %v\", p, gsACL)\n\t\t} else {\n\t\t\tklog.V(4).Infof(\"Writing file %q\", p)\n\t\t}\n\n\t\tif _, err := data.Seek(0, 0); err != nil {\n\t\t\treturn false, fmt.Errorf(\"error seeking to start of data stream for write to %s: %v\", p, err)\n\t\t}\n\n\t\tclient, err := p.getStorageClient(ctx)\n\t\tif err != nil {\n\t\t\treturn false, err\n\t\t}\n\n\t\tw := client.Bucket(p.bucket).Object(p.key).NewWriter(ctx)\n\t\t// The upload is rejected if the data does not match this MD5 hash","sourceCodeStart":170,"sourceCodeEnd":206,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/util/pkg/vfs/gsfs.go#L170-L206","documentation":"GSPath.WriteFile expects the ACL argument to be a *GSAcl, the Google-Storage-specific ACL implementation in this package. If a caller passes an ACL built for a different VFS backend (e.g. *S3Acl, *SSHAcl, *VFSAcl), it fails immediately with this message inside the retry closure. This is a programming error: ACL types are backend-specific and must match the path type.","triggerScenarios":"Calling GSPath.WriteFile(ctx, data, acl) with a non-nil acl that is not *GSAcl — typically constructed via vfs.NewACL(\"s3\") (or another provider) while writing to a gs:// path, or passing an ACL object obtained from an S3/FS path into GCS write code.","commonSituations":"Code that is cloud-agnostic but hardcodes one ACL (common when porting an AWS tool to GCP); a config option like --acl fed straight into WriteFile without mapping to the backend; tests or shared helpers reusing a single ACL value across backends.","solutions":["Construct the ACL for the GCS backend: use vfs.NewACL(\"gs\") (or &vfs.GSAcl{Acl: []storage.ACLRule{...}}) instead of the S3/other-backend ACL type.","If the code supports multiple backends, select the ACL based on the path type: switch p.(type) { case *vfs.GSPath: acl = vfs.NewACL(\"gs\"); case *vfs.S3Path: acl = vfs.NewACL(\"s3\") }.","If no special ACL is required, pass nil — WriteFile then writes with the bucket's default object ACL and skips the type check entirely."],"exampleFix":"// before\nacl := vfs.NewACL(\"s3\")            // S3Acl\ngsPath.WriteFile(ctx, data, acl)   // panics into \"ACL of unexpected type\"\n// after\nacl := vfs.NewACL(\"gs\")            // *GSAcl, matches gs:// path\ngsPath.WriteFile(ctx, data, acl)","handlingStrategy":"validation","validationCode":"// Validate the ACL type before calling WriteFile:\nfunc validateACL(p vfs.Path, acl vfs.ACL) error {\n    if acl == nil {\n        return nil // nil is always accepted\n    }\n    if _, ok := p.(*vfs.GSPath); ok {\n        if _, ok := acl.(*vfs.GSAcl); !ok {\n            return fmt.Errorf(\"gs:// path requires *vfs.GSAcl, got %T\", acl)\n        }\n    }\n    return nil\n}","typeGuard":"func isGSAcl(acl vfs.ACL) bool {\n    _, ok := acl.(*vfs.GSAcl)\n    return ok\n}","tryCatchPattern":"if err := gsPath.WriteFile(ctx, data, acl); err != nil {\n    if strings.Contains(err.Error(), \"ACL of unexpected type\") {\n        // programmer error: rebuild ACL for the GCS backend and retry once\n        if werr := gsPath.WriteFile(ctx, data, vfs.NewACL(\"gs\")); werr != nil {\n            return werr\n        }\n        return nil\n    }\n    return err\n}","preventionTips":["Always create ACLs with vfs.NewACL(provider) matching the backend of the path being written (\"gs\" for GSPath).","Never reuse a single ACL value across S3/GCS/FS paths in shared helpers.","Pass nil when the bucket default ACL is acceptable — it bypasses the type check.","Add a unit test asserting the ACL type passed to backend-specific write helpers."],"tags":["gcs","acl","type-error","kops","golang"],"backgroundTag":"wrong-acl-type","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}