hashicorp/terraform · warning
acl value invalid, expected %s or %s, got %s
Error message
acl value invalid, expected %s or %s, got %s
What it means
ValidateFunc for the cos backend's `acl` attribute (cos/backend.go:167). Only 'private' and 'public-read' are accepted; any other ACL string fails validation. State files contain secrets, so 'private' is the safe default.
Source
Thrown at internal/backend/remote-state/cos/backend.go:167
}
return nil, nil
},
},
"encrypt": {
Type: schema.TypeBool,
Optional: true,
Description: "Whether to enable server side encryption of the state file",
Default: true,
},
"acl": {
Type: schema.TypeString,
Optional: true,
Description: "Object ACL to be applied to the state file",
Default: "private",
ValidateFunc: func(v interface{}, s string) ([]string, []error) {
value := v.(string)
if value != "private" && value != "public-read" {
return nil, []error{fmt.Errorf(
"acl value invalid, expected %s or %s, got %s",
"private", "public-read", value)}
}
return nil, nil
},
},
"accelerate": {
Type: schema.TypeBool,
Optional: true,
Description: "Whether to enable global Acceleration",
Default: false,
},
"assume_role": {
Type: schema.TypeSet,
Optional: true,
MaxItems: 1,
Description: "The `assume_role` block. If provided, terraform will attempt to assume this role using the supplied credentials.",
Elem: &schema.Resource{View on GitHub (pinned to c9def3e214)
Solutions
- Set acl = "private" (the default and recommended value for state).
- Use acl = "public-read" only if you have a specific reason and understand state exposure.
- Do not use S3-only ACL names; COS supports a narrower set.
Example fix
// before
terraform {
backend "cos" {
acl = "public-read-write"
}
}
// after
terraform {
backend "cos" {
acl = "private"
}
} Defensive patterns
Strategy: validation
Validate before calling
// Validate the cos acl value before passing it to the backend
func validACL(v string) error {
if v != "private" && v != "public-read" {
return fmt.Errorf("acl must be 'private' or 'public-read', got %q", v)
}
return nil
} Type guard
// isSupportedCosACL narrows a string to an allowed COS ACL
func isSupportedCosACL(v string) bool {
return v == "private" || v == "public-read"
} Prevention
- Default to 'private' for state - it contains secrets.
- Do not assume S3 ACL names map 1:1 to COS.
- Review ACL in code review when sharing backend configs.
When it happens
Trigger: Setting acl to anything other than 'private' or 'public-read' (e.g. 'public-read-write', 'bucket-owner-full-control') in the backend block.
Common situations: Carrying over an S3-style ACL value; assuming full AWS S3 ACL names are supported; accidentally exposing state with a public ACL.
Related errors
- prefix must not start with '/' or './'
- key can not start and end with '/'
- %q cannot be lower than %d: %d
- %q cannot be higher than %d: %d
- Invalid URL: %v must be: %v
AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07).
Data as JSON: /api/errors/2c9a76d2b5c5507d.
Report an issue: GitHub.