hashicorp/terraform · error

invalid value for

Error message

invalid value for %q: %s

What it means

Thrown by SDKLikeDefaults.ApplyTo in the cty.Bool case when strconv.ParseBool rejects the resolved string. HCL config values for bool attributes are already validated by HCL, so this error almost always comes from an environment variable or a Fallback default that is not a recognized bool literal. strconv.ParseBool only accepts 1, t, T, TRUE, true, True, 0, f, F, FALSE, false, False.

Solutions

  1. Change the env var to a strconv.ParseBool-accepted literal: "true"/"false" (or "1"/"0").
  2. Set the bool attribute directly in the backend block (HCL accepts true/false natively).
  3. If you maintain a backend, document the accepted bool spellings next to the EnvVars entry to prevent the yes/no trap.
  4. Unset the env var if the default ("false" when rawStr is empty) is what you want.

Example fix

# before
export TF_SKIP_VERIFY="yes"     # -> invalid value for "skip_credentials_validation"
# after
export TF_SKIP_VERIFY="true"
Defensive patterns

Strategy: validation

Validate before calling

// Validate bool env vars with the same rule ApplyTo uses.
func boolEnvOk(name string) error {
    if v := os.Getenv(name); v != "" {
        if _, err := strconv.ParseBool(v); err != nil {
            return fmt.Errorf("env %s=%q is not a valid bool (want true/false/1/0)", name, v)
        }
    }
    return nil
}

Type guard

null

Try / catch

if _, err := defs.ApplyTo(cfg); err != nil {
    // Distinguish bool-parse errors by substring if you want bespoke UX.
    if strings.Contains(err.Error(), "invalid value for") {
        return fmt.Errorf("a backend env var has an invalid bool value: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: An attribute typed cty.Bool has defs.EnvVars set; the user exports that env var with a value like "yes", "no", "enabled", "on", "off", or "y". ApplyTo resolves rawStr to that value, then strconv.ParseBool(rawStr) returns an error and the message is `invalid value for "<attrName>": <strconv error>`.

Common situations: Using common shell idioms (yes/no, on/off) for a boolean backend flag such as use_azuread_auth, skip_credentials_validation, or force_path_style. Also seen when an env var is accidentally set to a descriptive sentence or to a numeric other than 0/1.

Related errors


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

Appendix: source

Thrown at internal/backend/backendbase/sdklike.go:262

		// also unset. Otherwise, rawStr contains a string representation of
		// a value that we now need to convert back to the type that was
		// originally wanted.
		switch ty {
		case cty.String:
			retAttrs[attrName] = cty.StringVal(rawStr)
		case cty.Bool:
			if rawStr == "" {
				rawStr = "false"
			}

			// Legacy SDK uses strconv.ParseBool and therefore tolerates a
			// variety of different string representations of true and false,
			// so we'll do the same here. The config itself can't use those
			// alternate forms because HCL's definition of bool prevails there,
			// but the environment variables can use any of these forms.
			bv, err := strconv.ParseBool(rawStr)
			if err != nil {
				return cty.NilVal, fmt.Errorf("invalid value for %q: %s", attrName, err)
			}
			retAttrs[attrName] = cty.BoolVal(bv)
		case cty.Number:
			if rawStr == "" {
				rawStr = "0"
			}

			// This case is a little trickier because cty.Number could be
			// representing either an integer or a float, which each have
			// different interpretations in the legacy SDK. Therefore we'll
			// try integer first and use its result if successful, but then
			// try float as a fallback if not.
			if iv, err := strconv.ParseInt(rawStr, 0, 0); err == nil {
				retAttrs[attrName] = cty.NumberIntVal(iv)
			} else if fv, err := strconv.ParseFloat(rawStr, 64); err == nil {
				retAttrs[attrName] = cty.NumberFloatVal(fv)
			} else {
				return cty.NilVal, fmt.Errorf("invalid value for %q: must be a number", attrName)

View on GitHub (pinned to d32a084675)