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

  1. Set prefix to a bare path with no leading slash or './', e.g. 'terraform/prod'.
  2. 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

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


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)