hashicorp/terraform · error

failed to parse unlock_address URL

Error message

failed to parse unlock_address URL: %s

What it means

url.Parse returned an error for the unlock_address value (attribute or TF_HTTP_UNLOCK_ADDRESS). The string is malformed: control characters, raw spaces, invalid percent-encoding, or unbalanced brackets. unlock_address is optional and only validated when non-null.

Solutions

  1. Percent-encode spaces/special characters in unlock_address.
  2. Ensure the value is a single line with no control characters.
  3. Use an absolute http(s) URL with the same shape as lock_address.
  4. Validate with: printf '%s' "$TF_HTTP_UNLOCK_ADDRESS" | grep -P '[\x00-\x1f]'.

Example fix

// before
unlock_address = "https://state.example.com/unlock?id=1 2"
// after
unlock_address = "https://state.example.com/unlock?id=1%202"
Defensive patterns

Strategy: validation

Validate before calling

# Pre-flight: validate unlock_address
if [ -n "$TF_HTTP_UNLOCK_ADDRESS" ]; then
  printf '%s' "$TF_HTTP_UNLOCK_ADDRESS" | grep -P '[\x00-\x1f]' && { echo 'control chars in unlock_address'; exit 1; }
  case "$TF_HTTP_UNLOCK_ADDRESS" in http://*|https://*) ;; *) echo 'unlock_address missing http(s) scheme'; exit 1;; esac
fi

Prevention

When it happens

Trigger: unlock_address contains raw spaces/control characters, an invalid '%' escape, or a stray newline; copy-paste across systems introduced invisible characters.

Common situations: unlock_address templated without encoding; env var carrying trailing whitespace; mixed encoding between lock_address and unlock_address.

Understand the failure class

Related errors


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

Appendix: 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 d32a084675)