hashicorp/terraform · error
prefix must not start with '/' or './'
Error message
prefix must not start with '/' or './'
What it means
Schema-level ValidateFunc for the COS backend 'prefix' attribute. The prefix is joined with the key to form the object key (path.Join(b.prefix, b.key)), so a leading '/' or './' would produce unintended object keys. The validator rejects those prefixes at terraform init time.
Solutions
- Set prefix to a bare path with no leading slash or './', e.g. 'terraform/prod'.
- Re-run terraform init with the corrected backend configuration.
Example fix
// before
terraform {
backend "cos" {
prefix = "/terraform/prod"
}
}
// after
terraform {
backend "cos" {
prefix = "terraform/prod"
}
} Defensive patterns
Strategy: validation
Validate before calling
// Validate the COS backend prefix before terraform init.
func validateCOSPrefix(prefix string) error {
if strings.HasPrefix(prefix, "/") || strings.HasPrefix(prefix, "./") {
return fmt.Errorf("prefix must not start with '/' or './'")
}
return nil
} Prevention
- Treat COS prefix as a bare relative path (e.g. 'terraform/prod'), not an absolute one.
- Validate backend blocks in CI with `terraform init -backend=false` then a config-lint pass.
- Don't copy S3 backend paths verbatim; S3 tolerates a leading slash, COS does not.
- Document the prefix convention in the team's backend module.
When it happens
Trigger: terraform init with a `prefix` value whose first character is '/' or whose first two characters are './'.
Common situations: User copy-pastes an absolute path like '/terraform/prod' from an S3 backend config; uses POSIX-relative notation './envs'; assumes leading slash is required like AWS S3.
Related errors
- acl value invalid, expected
- Invalid URL: must be
- key can not start and end with '/'
- cannot be higher than
- cannot be lower than
AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11).
Data as JSON: /api/errors/18e69fa96a869340.
Report an issue: GitHub.
Appendix: source
Thrown at internal/backend/remote-state/cos/backend.go:136
Type: schema.TypeString,
Optional: true,
Description: "The custom endpoint for the COS API, e.g. http://cos-internal.{Region}.tencentcos.cn. Both HTTP and HTTPS are accepted.",
DefaultFunc: schema.EnvDefaultFunc(PROVIDER_ENDPOINT, nil),
},
"domain": {
Type: schema.TypeString,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc(PROVIDER_DOMAIN, nil),
Description: "The root domain of the API request. Default is tencentcloudapi.com.",
},
"prefix": {
Type: schema.TypeString,
Optional: true,
Description: "The directory for saving the state file in bucket",
ValidateFunc: func(v interface{}, s string) ([]string, []error) {
prefix := v.(string)
if strings.HasPrefix(prefix, "/") || strings.HasPrefix(prefix, "./") {
return nil, []error{fmt.Errorf("prefix must not start with '/' or './'")}
}
return nil, nil
},
},
"key": {
Type: schema.TypeString,
Optional: true,
Description: "The path for saving the state file in bucket",
Default: "terraform.tfstate",
ValidateFunc: func(v interface{}, s string) ([]string, []error) {
if strings.HasPrefix(v.(string), "/") || strings.HasSuffix(v.(string), "/") {
return nil, []error{fmt.Errorf("key can not start and end with '/'")}
}
return nil, nil
},
},
"encrypt": {
Type: schema.TypeBool,View on GitHub (pinned to d32a084675)