kubernetes/kops · error
write to %s with ACL of unexpected type %T
Error message
write to %s with ACL of unexpected type %T
What it means
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.
Source
Thrown at util/pkg/vfs/gsfs.go:188
return &GSPath{
vfsContext: p.vfsContext,
bucket: p.bucket,
key: joined,
}
}
func (p *GSPath) WriteFile(ctx context.Context, data io.ReadSeeker, acl ACL) error {
md5Hash, err := hashing.HashAlgorithmMD5.Hash(data)
if err != nil {
return err
}
done, err := RetryWithBackoff(gcsWriteBackoff, func() (bool, error) {
var objectACL []storage.ACLRule
if acl != nil {
gsACL, ok := acl.(*GSAcl)
if !ok {
return true, fmt.Errorf("write to %s with ACL of unexpected type %T", p, acl)
}
objectACL = gsACL.Acl
klog.V(4).Infof("Writing file %q with ACL %v", p, gsACL)
} else {
klog.V(4).Infof("Writing file %q", p)
}
if _, err := data.Seek(0, 0); err != nil {
return false, fmt.Errorf("error seeking to start of data stream for write to %s: %v", p, err)
}
client, err := p.getStorageClient(ctx)
if err != nil {
return false, err
}
w := client.Bucket(p.bucket).Object(p.key).NewWriter(ctx)
// The upload is rejected if the data does not match this MD5 hashView on GitHub (pinned to 4c8573c808)
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.
Example fix
// before
acl := vfs.NewACL("s3") // S3Acl
gsPath.WriteFile(ctx, data, acl) // panics into "ACL of unexpected type"
// after
acl := vfs.NewACL("gs") // *GSAcl, matches gs:// path
gsPath.WriteFile(ctx, data, acl) Defensive patterns
Strategy: validation
Validate before calling
// Validate the ACL type before calling WriteFile:
func validateACL(p vfs.Path, acl vfs.ACL) error {
if acl == nil {
return nil // nil is always accepted
}
if _, ok := p.(*vfs.GSPath); ok {
if _, ok := acl.(*vfs.GSAcl); !ok {
return fmt.Errorf("gs:// path requires *vfs.GSAcl, got %T", acl)
}
}
return nil
} Type guard
func isGSAcl(acl vfs.ACL) bool {
_, ok := acl.(*vfs.GSAcl)
return ok
} Try / catch
if err := gsPath.WriteFile(ctx, data, acl); err != nil {
if strings.Contains(err.Error(), "ACL of unexpected type") {
// programmer error: rebuild ACL for the GCS backend and retry once
if werr := gsPath.WriteFile(ctx, data, vfs.NewACL("gs")); werr != nil {
return werr
}
return nil
}
return err
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- error seeking to start of data stream for write to %s: %v
- building VFS path for %q: %w
- error checking GCS bucket ACL for gs://%s for %s: %v
- error setting GCS bucket ACL for gs://%s for %s as %s: %v
- error removing file %s: %w
AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05).
Data as JSON: /api/errors/3bd16b4c18ff4920.
Report an issue: GitHub.