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

getRequestACL converts the vfs ACL option into an S3 request ACL. If the ACL passed via vfs ACL option is not *S3Acl (and not a plain canned-ACL string), the write is aborted with "write to <path> with ACL of unexpected type %T". This is a programming error: the caller supplied an ACL type meant for a different backend.

Source

Thrown at util/pkg/vfs/s3fs.go:311

			sseLog = "AES256"
			sse = types.ServerSideEncryptionAes256
		}
	}

	return sse, sseLog, nil
}

func (p *S3Path) getRequestACL(aclObj ACL) (*types.ObjectCannedACL, error) {
	acl := os.Getenv("KOPS_STATE_S3_ACL")
	acl = strings.TrimSpace(acl)
	if acl != "" {
		cannedACL := types.ObjectCannedACL(acl)
		klog.V(8).Infof("Using KOPS_STATE_S3_ACL=%s", acl)
		return &cannedACL, nil
	} else if aclObj != nil {
		s3Acl, ok := aclObj.(*S3Acl)
		if !ok {
			return nil, fmt.Errorf("write to %s with ACL of unexpected type %T", p, aclObj)
		}
		return s3Acl.RequestACL, nil
	}
	return nil, nil
}

func (p *S3Path) WriteFile(ctx context.Context, data io.ReadSeeker, aclObj ACL) error {
	ctx, span := tracer.Start(ctx, "S3Path::WriteFile", trace.WithAttributes(attribute.String("path", p.String())))
	defer span.End()

	client, err := p.client(ctx)
	if err != nil {
		return err
	}

	klog.V(4).Infof("Writing file %q", p)

	request := &s3.PutObjectInput{}

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Pass *vfs.S3Acl (constructed with the desired types.ObjectCannedACL) when writing to S3 paths
  2. Alternatively pass the canned ACL as a plain string (handled by the KOPS_STATE_S3_ACL string branch) or set the KOPS_STATE_S3_ACL env var and omit the option
  3. Audit generic write helpers to select the backend-specific ACL type based on the path type

Example fix

// before
err = vfs.Context.WriteFile(p, data, vfsopt.WithACL(gcutil.NewAcl("project-owner")))
// after
err = vfs.Context.WriteFile(p, data, vfsopt.WithACL(vfs.NewS3Acl("private")))
Defensive patterns

Strategy: validation

Validate before calling

switch acl := opt.(type) {
case *vfs.S3Acl:
	// ok
case string:
	// ok, canned ACL
default:
	return fmt.Errorf("backend %T needs a backend-specific ACL, got %T", p, opt)
}

Type guard

func isS3Acl(a any) bool { _, ok := a.(*vfs.S3Acl); return ok }

Try / catch

if err := vfs.Context.WriteFile(p, data, opts...); err != nil {
	if strings.Contains(err.Error(), "ACL of unexpected type") {
		return rebuildOptionsForBackend(p, data)
	}
	return err
}

Prevention

When it happens

Trigger: Calling WriteFile (directly or via CreateFile) with an ACL option set to e.g. *GSAcl, *azure ACL type, or any non-*S3Acl object while writing to an S3 path.

Common situations: Generic tooling that applies the same vfs.ACL option across cloud backends; copy-pasted code passing a GCS ACL to an S3 state store; custom vfs wrappers constructing the wrong ACL struct.

Related errors


AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05). Data as JSON: /api/errors/0b1a67a8831320bd. Report an issue: GitHub.