hashicorp/terraform · error

expected type of %s to be int

Error message

expected type of %s to be int

What it means

Emitted from the ValidateFunc of session_expiration inside the deprecated assume_role schema block. It fires when the value passed cannot be asserted to int. Because the schema field is declared schema.TypeInt, Terraform normally coerces the value, so reaching this branch indicates a non-coercible type slipped through (programmatic config, raw cty, or a malformed HCL variable).

Source

Thrown at internal/backend/remote-state/oss/backend.go:75

					Optional:    true,
					Description: "The session name to use when assuming the role.",
					DefaultFunc: schema.MultiEnvDefaultFunc([]string{"ALICLOUD_ASSUME_ROLE_SESSION_NAME", "ALIBABA_CLOUD_ROLE_SESSION_NAME"}, ""),
				},
				"policy": {
					Type:        schema.TypeString,
					Optional:    true,
					Description: "The permissions applied when assuming a role. You cannot use this policy to grant permissions which exceed those of the role that is being assumed.",
				},
				"session_expiration": {
					Type:        schema.TypeInt,
					Optional:    true,
					Description: "The time after which the established session for assuming role expires.",
					ValidateFunc: func(v interface{}, k string) ([]string, []error) {
						min := 900
						max := 3600
						value, ok := v.(int)
						if !ok {
							return nil, []error{fmt.Errorf("expected type of %s to be int", k)}
						}

						if value < min || value > max {
							return nil, []error{fmt.Errorf("expected %s to be in the range (%d - %d), got %d", k, min, max, v)}
						}

						return nil, nil
					},
				},
			},
		},
	}
}

// New creates a new backend for OSS remote state.
func New() backend.Backend {
	s := &schema.Backend{
		Schema: map[string]*schema.Schema{

View on GitHub (pinned to c9def3e214)

Solutions

  1. Provide session_expiration as a bare integer literal in HCL (e.g. session_expiration = 3600), not a quoted string.
  2. If sourcing from a variable, declare it as type = number and pass an unquoted value.
  3. Migrate off the deprecated assume_role block to the top-level assume_role_session_expiration attribute which shares the same validator.
  4. Ensure the value is also within 900–3600 (see error 323) once the type is fixed.

Example fix

# before
assume_role {
  session_expiration = "3600"   # string -> type error
}

# after
assume_role {
  session_expiration = 3600     # integer seconds
}
Defensive patterns

Strategy: validation

Validate before calling

// In your wrapper, coerce before passing to the schema.
func asInt(v interface{}) (int, error) {
    switch n := v.(type) {
    case int:    return n, nil
    case float64: return int(n), nil
    case string: return strconv.Atoi(n)
    }
    return 0, fmt.Errorf("expected int, got %T", v)
}

Type guard

func isInt(v interface{}) bool { _, ok := v.(int); return ok }

Prevention

When it happens

Trigger: Setting assume_role.session_expiration to a non-integer (a string like "3600s", a float, or null) via a variable/programmatic backend config that bypasses the schema's normal int coercion. The ValidateFunc receives the raw interface{} and the v.(int) type assertion fails.

Common situations: Variable interpolation producing a string instead of a number; using assume_role blocks from an older example; tooling that builds the backend config from JSON without coercing types.

Related errors


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