{"record":{"id":"4139b658032555cd","repo":"kubernetes/kops","slug":"unexpected-acl-type-t","errorCode":null,"errorMessage":"unexpected acl type %T","messagePattern":"unexpected acl type %T","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"util/pkg/vfs/sshfs.go","lineNumber":223,"sourceCode":"\t\t\t// Something went wrong; try to remove the temp file\n\t\t\tif err := sftpClient.Remove(tempfile); err != nil {\n\t\t\t\tklog.Warningf(\"unable to remove temp file %q: %v\", tempfile, err)\n\t\t\t}\n\t\t}\n\t}()\n\tif _, err := io.Copy(f, data); err != nil {\n\t\treturn fmt.Errorf(\"writing to sftp temp file: %w\", err)\n\t}\n\n\tshouldClose = false\n\tif err := f.Close(); err != nil {\n\t\treturn err\n\t}\n\n\tif acl != nil {\n\t\tsshACL, ok := acl.(*SSHAcl)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"unexpected acl type %T\", acl)\n\t\t} else {\n\t\t\terr = sftpClient.Chmod(tempfile, sshACL.Mode)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error during chmod of %q: %w\", tempfile, err)\n\t\t\t}\n\t\t}\n\t}\n\n\t// posix rename will replace the destination (normal sftp rename does not)\n\tusePosixRename := true\n\tif usePosixRename {\n\t\t// posix rename fails if destination exists, try to delete just in case\n\t\tif err := sftpClient.Remove(p.path); err != nil {\n\t\t\tif os.IsNotExist(err) {\n\t\t\t\t// expected when file does not exist already\n\t\t\t} else {\n\t\t\t\treturn fmt.Errorf(\"removing destination sftp file %q before rename: %w\", p.path, err)\n\t\t\t}","sourceCodeStart":205,"sourceCodeEnd":241,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/util/pkg/vfs/sshfs.go#L205-L241","documentation":"WriteFile accepts an ACL of the vfs package's ACL interface type. For SSH paths the only valid non-nil ACL is *SSHAcl, which carries a permission Mode. If the caller passes any other ACL implementation (e.g. *S3Acl, *VFSAcl from a different backend), the type assertion fails and this error is returned before chmod.","triggerScenarios":"Calling WriteFile/CreateFile on an SSHPath with acl set to a non-nil value that is not *vfs.SSHAcl — e.g. reusing an ACL object constructed for S3/GS/DO paths.","commonSituations":"Generic vfs code paths that build an ACL for one backend and pass it to another; copy-pasted code switching from s3:// to ssh:// targets; custom ACL implementations not deriving from SSHAcl.","solutions":["Pass vfs.NewSSHAcl(mode) (e.g. os.FileMode(0o600)) when writing to SSHPath targets.","Pass nil as the acl argument if no special permissions are needed.","If ACLs come from generic code, branch on the path type and build the backend-appropriate ACL.","Inspect the %T in the error to identify exactly which ACL type was wrongly supplied."],"exampleFix":"// before\npath.WriteFile(ctx, data, vfs.NewS3Acl(\"private\")) // wrong backend ACL\n// after\npath.WriteFile(ctx, data, vfs.NewSSHAcl(0o600))","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"func isSSHAcl(acl vfs.ACL) (*vfs.SSHAcl, bool) {\n    if acl == nil { return nil, false }\n    a, ok := acl.(*vfs.SSHAcl)\n    return a, ok\n}","tryCatchPattern":"err := path.WriteFile(ctx, data, acl)\nif err != nil && strings.Contains(err.Error(), \"unexpected acl type\") {\n    // rebuild acl for SSH backend\n    return path.WriteFile(ctx, data, vfs.NewSSHAcl(0o600))\n}","preventionTips":["Use backend-specific constructors (NewSSHAcl for SSHPath) at the call site.","Centralize ACL creation in one helper that switches on path type.","Pass nil instead of a foreign backend's ACL when permissions don't matter."],"tags":["go","type-assertion","acl","ssh"],"backgroundTag":"acl-type-mismatch","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"}