hashicorp/terraform · error

either a string or an integer is required

Error message

either a string or an integer is required

What it means

Returned by addrs.ParseInstanceKey when the supplied cty.Value's type is neither cty.String nor cty.Number — i.e. it cannot be used as a count index (int) or for_each key (string). ParseInstanceKey is explicitly documented to panic on null/unknown and to error on any other type via this message.

Solutions

  1. Ensure the value passed to ParseInstanceKey is known, non-null, and of type cty.String or cty.Number.
  2. Add a type guard (key.Type() == cty.String || key.Type() == cty.Number) before calling.
  3. If you hold an hcl.TraverseIndex, extract its key only after confirming the traversal source; do not construct cty values of other types.
  4. For unknown/null inputs, decide on a sentinel (NoKey / WildcardKey) before invoking ParseInstanceKey, since it panics on those.

Example fix

// before
k, err := addrs.ParseInstanceKey(maybeVal)

// after
if maybeVal.Type() != cty.String && maybeVal.Type() != cty.Number {
    return addrs.NoKey, fmt.Errorf("instance key must be string or number, got %s", maybeVal.Type().FriendlyName())
}
k, err := addrs.ParseInstanceKey(maybeVal)
Defensive patterns

Strategy: type-guard

Validate before calling

// Narrow the type before parsing
if key.IsNull() || !key.IsKnown() {
    return addrs.NoKey, errors.New("instance key must be known and non-null")
}

Type guard

func isParsableInstanceKey(v cty.Value) bool {
    t := v.Type()
    return (t == cty.String || t == cty.Number) && !v.IsNull() && v.IsKnown()
}

Try / catch

if !isParsableInstanceKey(v) {
    return addrs.NoKey, fmt.Errorf("instance key must be a known, non-null string or number, got %s", v.Type().FriendlyName())
}
k, err := addrs.ParseInstanceKey(v)

Prevention

When it happens

Trigger: Calling ParseInstanceKey with a cty.Value of an unexpected type (bool, list, object, dynamic pseudo-type). Naturally reached from hcl.TraverseIndex parsing, which only ever yields string/number, so seeing this error implies programmatic misuse.

Common situations: Custom code building instance keys from arbitrary cty values without first narrowing the type; a schema change feeding a non-scalar into a traversal index; downstream code re-parsing an already-keyed address with the wrong value kind.

Related errors


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

Appendix: source

Thrown at internal/addrs/instance_key.go:48

}

// ParseInstanceKey returns the instance key corresponding to the given value,
// which must be known and non-null.
//
// If an unknown or null value is provided then this function will panic. This
// function is intended to deal with the values that would naturally be found
// in a hcl.TraverseIndex, which (when parsed from source, at least) can never
// contain unknown or null values.
func ParseInstanceKey(key cty.Value) (InstanceKey, error) {
	switch key.Type() {
	case cty.String:
		return StringKey(key.AsString()), nil
	case cty.Number:
		var idx int
		err := gocty.FromCtyValue(key, &idx)
		return IntKey(idx), err
	default:
		return NoKey, fmt.Errorf("either a string or an integer is required")
	}
}

// NoKey represents the absense of an InstanceKey, for the single instance
// of a configuration object that does not use "count" or "for_each" at all.
var NoKey InstanceKey

// WildcardKey represents the "unknown" value of an InstanceKey. This is used
// within the deferral logic to express absolute module and resource addresses
// that are not known at the time of planning.
var WildcardKey InstanceKey = &wildcardKey{}

// wildcardKey is a special kind of InstanceKey that represents the "unknown"
// value of an InstanceKey. This is used within the deferral logic to express
// absolute module and resource addresses that are not known at the time of
// planning.
type wildcardKey struct{}

View on GitHub (pinned to d32a084675)