{"record":{"id":"c71113044f0064e1","repo":"kubernetes/kops","slug":"expected-acl-to-be-s3acl-was-t","errorCode":null,"errorMessage":"expected acl to be S3Acl, was %T","messagePattern":"expected acl to be S3Acl, was %T","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"util/pkg/vfs/memfs.go","lineNumber":221,"sourceCode":"\n\treturn nil\n}\n\nfunc (p *MemFSPath) RemoveAllVersions(ctx context.Context) error {\n\treturn p.Remove(ctx)\n}\n\nfunc (p *MemFSPath) Location() string {\n\treturn p.location\n}\n\nfunc (p *MemFSPath) IsPublic() (bool, error) {\n\tif p.acl == nil {\n\t\treturn false, nil\n\t}\n\ts3Acl, ok := p.acl.(*S3Acl)\n\tif !ok {\n\t\treturn false, fmt.Errorf(\"expected acl to be S3Acl, was %T\", p.acl)\n\t}\n\tisPublic := false\n\tif s3Acl.RequestACL != nil {\n\t\tisPublic = *s3Acl.RequestACL == \"public-read\"\n\t}\n\treturn isPublic, nil\n}\n\ntype terraformMemFSFile struct {\n\tBucket   string                   `json:\"bucket\" cty:\"bucket\"`\n\tKey      string                   `json:\"key\" cty:\"key\"`\n\tContent  *terraformWriter.Literal `json:\"content,omitempty\" cty:\"content\"`\n\tAcl      *string                  `json:\"acl,omitempty\" cty:\"acl\"`\n\tSSE      string                   `json:\"server_side_encryption,omitempty\" cty:\"server_side_encryption\"`\n\tProvider *terraformWriter.Literal `json:\"provider,omitempty\" cty:\"provider\"`\n}\n\nfunc (p *MemFSPath) RenderTerraform(w *terraformWriter.TerraformWriter, name string, data io.Reader, acl ACL) error {","sourceCodeStart":203,"sourceCodeEnd":239,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/util/pkg/vfs/memfs.go#L203-L239","documentation":"MemFSPath.IsPublic only understands S3-style ACLs; it type-asserts the path's stored ACL to *S3Acl and fails if the concrete type differs. Since MemFS reuses S3Acl as its ACL representation, any other ACL type (e.g. a GCS-style ACL) is rejected.","triggerScenarios":"Setting a path's ACL with a non-*S3Acl value (e.g. in tests) and then calling IsPublic on that path while the ACL is non-nil.","commonSituations":"Test code constructing memfs paths with custom/mock ACL types; code paths ported from GCS that attach gsutil-style ACLs; refactors introducing a new ACL type not handled by IsPublic's assertion.","solutions":["Store ACLs on MemFSPath as *vfs.S3Acl (e.g. vfs.NewACL(...)/S3Acl with RequestACL set) instead of a custom type","If the ACL truly is another type, extend IsPublic (or the caller) to handle it instead of relying on the S3 assertion","Skip the IsPublic check when the ACL type is unknown; treat as not-public only for *S3Acl"],"exampleFix":"// before\np.SetACL(ctx, myCustomACL{...})\np.IsPublic() // panics into error: expected acl to be S3Acl\n// after\np.SetACL(ctx, &vfs.S3Acl{RequestACL: ptr.To(\"public-read\")})\nisPublic, err := p.IsPublic()","handlingStrategy":"type-guard","validationCode":"func aclIsPublicSafe(acl vfs.ACL) (bool, error) { if acl == nil { return false, nil }; s3, ok := acl.(*vfs.S3Acl); if !ok { return false, nil }; return s3.RequestACL != nil && *s3.RequestACL == \"public-read\", nil }","typeGuard":"func asS3Acl(acl vfs.ACL) (*vfs.S3Acl, bool) { s, ok := acl.(*vfs.S3Acl); return s, ok }","tryCatchPattern":"isPublic, err := p.IsPublic()\nif err != nil && strings.Contains(err.Error(), \"expected acl to be S3Acl\") {\n    return false, nil // non-S3 ACL: treat as not public\n}","preventionTips":["Only attach *vfs.S3Acl values to MemFS paths","Verify ACL concrete types in tests before asserting IsPublic","Centralize ACL construction through vfs helpers rather than ad-hoc structs"],"tags":["vfs","memfs","acl","type-assertion"],"backgroundTag":"unexpected-acl-type","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T07:17:12.445Z"}