hashicorp/terraform · error

failed to parse unlock_address URL: %s

Error message

failed to parse unlock_address URL: %s

What it means

Thrown by the HTTP backend's Configure step when url.Parse() rejects the value supplied via the unlock_address backend argument or the TF_HTTP_UNLOCK_ADDRESS env var. The '%s' carries the underlying net/url parse error, typically an unescaped control character, space, or malformed scheme delimiter. The unlock URL is only parsed when a value is provided (the attribute is optional), so this fires only on an explicitly configured unlock endpoint.

Source

Thrown at internal/backend/remote-state/http/backend.go:173

		}
		if lockURL.Scheme != "http" && lockURL.Scheme != "https" {
			return backendbase.ErrorAsDiagnostics(
				fmt.Errorf("lock_address must be HTTP or HTTPS"),
			)
		}
	}
	lockMethod := backendbase.GetAttrEnvDefaultFallback(
		configVal, "lock_method",
		"TF_HTTP_LOCK_METHOD", cty.StringVal("LOCK"),
	).AsString()

	var unlockURL *url.URL
	if v := backendbase.GetAttrEnvDefault(configVal, "unlock_address", "TF_HTTP_UNLOCK_ADDRESS"); !v.IsNull() {
		var err error
		unlockURL, err = url.Parse(v.AsString())
		if err != nil {
			return backendbase.ErrorAsDiagnostics(
				fmt.Errorf("failed to parse unlock_address URL: %s", err),
			)
		}
		if unlockURL.Scheme != "http" && unlockURL.Scheme != "https" {
			return backendbase.ErrorAsDiagnostics(
				fmt.Errorf("unlock_address must be HTTP or HTTPS"),
			)
		}
	}
	unlockMethod := backendbase.GetAttrEnvDefaultFallback(
		configVal, "unlock_method",
		"TF_HTTP_UNLOCK_METHOD", cty.StringVal("UNLOCK"),
	).AsString()

	retryMax, err := backendbase.IntValue(
		backendbase.GetAttrEnvDefaultFallback(
			configVal, "retry_max",
			"TF_HTTP_RETRY_MAX", cty.NumberIntVal(2),
		),

View on GitHub (pinned to c9def3e214)

Solutions

  1. Inspect the exact value in unlock_address (or TF_HTTP_UNLOCK_ADDRESS) and percent-encode any spaces or special characters.
  2. Ensure the value includes an explicit http:// or https:// scheme prefix.
  3. Validate the URL with `echo "$TF_HTTP_UNLOCK_ADDRESS" | xargs -n1 python3 -c 'import sys,urllib.parse;urllib.parse.urlparse(sys.argv[1])'` before running terraform.
  4. If the address is generated by a script, run it through url.PathEscape/url.QueryEscape for the path and query portions.

Example fix

// before
backend "http" {
  unlock_address = "http://state.corp/unlock my workspace"
}
// after
backend "http" {
  unlock_address = "http://state.corp/unlock%20my%20workspace"
}
Defensive patterns

Strategy: validation

Validate before calling

// Validate unlock_address before terraform init
import (
  "fmt"
  "net/url"
)
func validateUnlockURL(raw string) error {
  u, err := url.Parse(raw)
  if err != nil { return fmt.Errorf("unlock_address unparseable: %w", err) }
  if u.Scheme != "http" && u.Scheme != "https" {
    return fmt.Errorf("unlock_address scheme %q not allowed", u.Scheme)
  }
  return nil
}

Prevention

When it happens

Trigger: Setting unlock_address to a string with unencoded spaces (e.g. "http://host/unlock my state"), missing the scheme ("//host/unlock"), a raw IPv6 address without brackets, or any value net/url.Parse cannot accept. Triggered during `terraform init` or any run that re-configures the backend.

Common situations: Operators paste a URL containing spaces or query parameters into the unlock_address field without percent-encoding; CI sets TF_HTTP_UNLOCK_ADDRESS from an unescaped template variable; a trailing slash or stray character copied from a wiki.

Understand the failure class

Related errors


AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07). Data as JSON: /api/errors/c8bf6189840c67bc. Report an issue: GitHub.