hashicorp/terraform · error

must be a valid ACL value , expected , or , got

Error message

%q must be a valid ACL value , expected %s, %s or %s, got %q

What it means

Thrown by the ValidateFunc for the 'acl' field in the OSS backend when the provided ACL string is not one of the three valid values: oss.ACLPrivate, oss.ACLPublicRead, or oss.ACLPublicReadWrite. The error interpolates the valid values and the invalid value received.

Solutions

  1. Use one of the exact constant string values: oss.ACLPrivate, oss.ACLPublicRead, or oss.ACLPublicReadWrite.
  2. Leave the acl field empty (default is empty string, which skips the check) if you want bucket-default ACL.
  3. Check the aliyun-oss-go-sdk source or docs for the exact string values of these constants.

Example fix

// before (invalid ACL name)
terraform {
  backend "oss" {
    acl = "authenticated-read"
  }
}
// after
terraform {
  backend "oss" {
    acl = "private"
  }
}
Defensive patterns

Strategy: validation

Validate before calling

// Validate OSS ACL value before Terraform init
func validateOSSACL(acl string) error {
    if acl == "" {
        return nil // empty is allowed, uses bucket default
    }
    validACLs := map[string]bool{
        "private":            true,
        "public-read":        true,
        "public-read-write":  true,
    }
    if !validACLs[acl] {
        return fmt.Errorf("invalid ACL %q; must be one of: private, public-read, public-read-write", acl)
    }
    return nil
}

Prevention

When it happens

Trigger: ValidateFunc checks if value is non-empty, casts to oss.ACLType, and compares against the three valid constants. Fails when the user provides an unrecognized string like 'public', 'read-only', 'bucket-owner-read', or an AWS-style ACL like 'bucket-owner-full-control'.

Common situations: Developer uses an AWS S3 ACL name ('public-read-write' with different casing, or 'authenticated-read'). Developer uses a vague value like 'public' instead of 'public-read'. Copy-paste from S3 backend where ACL vocabulary differs. Case sensitivity issues ('Private' vs 'private').

Related errors


AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11). Data as JSON: /api/errors/71f373a0e037482a. Report an issue: GitHub.

Appendix: source

Thrown at internal/backend/remote-state/oss/backend.go:209

			},

			"encrypt": {
				Type:        schema.TypeBool,
				Optional:    true,
				Description: "Whether to enable server side encryption of the state file",
				Default:     false,
			},

			"acl": {
				Type:        schema.TypeString,
				Optional:    true,
				Description: "Object ACL to be applied to the state file",
				Default:     "",
				ValidateFunc: func(v interface{}, k string) ([]string, []error) {
					if value := v.(string); value != "" {
						acls := oss.ACLType(value)
						if acls != oss.ACLPrivate && acls != oss.ACLPublicRead && acls != oss.ACLPublicReadWrite {
							return nil, []error{fmt.Errorf(
								"%q must be a valid ACL value , expected %s, %s or %s, got %q",
								k, oss.ACLPrivate, oss.ACLPublicRead, oss.ACLPublicReadWrite, acls)}
						}
					}
					return nil, nil
				},
			},
			"shared_credentials_file": {
				Type:        schema.TypeString,
				Optional:    true,
				DefaultFunc: schema.MultiEnvDefaultFunc([]string{"ALICLOUD_SHARED_CREDENTIALS_FILE", "ALIBABA_CLOUD_CREDENTIALS_FILE"}, ""),
				Description: "This is the path to the shared credentials file. If this is not set and a profile is specified, `~/.aliyun/config.json` will be used.",
			},
			"profile": {
				Type:        schema.TypeString,
				Optional:    true,
				Description: "This is the Alibaba Cloud profile name as set in the shared credentials file. It can also be sourced from the `ALICLOUD_PROFILE` environment variable.",
				DefaultFunc: schema.MultiEnvDefaultFunc([]string{"ALICLOUD_PROFILE", "ALIBABA_CLOUD_PROFILE"}, ""),

View on GitHub (pinned to d32a084675)