hashicorp/terraform · error

invalid step %q with type %#v

Error message

invalid step %q with type %#v

What it means

Returned by pathFromFlatmapKeyValue (paths.go:136) when the declared type for the current path segment is a primitive (string/number/bool) but there is still a remaining key segment to navigate into. You cannot descend into a primitive — there are no sub-attributes — so any further path step is invalid.

Source

Thrown at internal/configs/hcl2shim/paths.go:136

	if rest == "" {
		return path, nil
	}

	p, err := pathFromFlatmapKeyValue(rest, ty)
	if err != nil {
		return path, err
	}

	return append(path, p...), nil
}

func pathFromFlatmapKeyValue(key string, ty cty.Type) (cty.Path, error) {
	var path cty.Path
	var err error

	switch {
	case ty.IsPrimitiveType():
		err = fmt.Errorf("invalid step %q with type %#v", key, ty)
	case ty.IsObjectType():
		path, err = pathFromFlatmapKeyObject(key, ty.AttributeTypes())
	case ty.IsTupleType():
		path, err = pathFromFlatmapKeyTuple(key, ty.TupleElementTypes())
	case ty.IsMapType():
		path, err = pathFromFlatmapKeyMap(key, ty)
	case ty.IsListType():
		path, err = pathFromFlatmapKeyList(key, ty)
	case ty.IsSetType():
		path, err = pathFromFlatmapKeySet(key, ty)
	default:
		err = fmt.Errorf("unrecognized type: %s", ty.FriendlyName())
	}

	if err != nil {
		return path, err
	}

View on GitHub (pinned to c9def3e214)

Solutions

  1. Compare the flatmap key depth against the schema: a primitive attribute must be a leaf — remove any extra '.N' or '.sub' segments on it.
  2. If the attribute legitimately became a collection, update the schema type and migrate the state key shape together.
  3. If the extra segment is spurious, clean the state file or re-apply to regenerate the diff.
  4. Pin the provider version matching the state if a schema type change caused the mismatch.

Example fix

// before — schema: name = cty.String
// state key: "name.0"  (cannot index into a string)

// after — keep scalar keys flat
"name": "my-instance"
Defensive patterns

Strategy: validation

Validate before calling

// Ensure primitive attributes are not given nested sub-keys
func noNestedPrimitiveKeys(keys []string, ty cty.Type) error {
    for name, aty := range ty.AttributeTypes() {
        if !aty.IsPrimitiveType() {
            continue
        }
        for _, k := range keys {
            if strings.HasPrefix(k, name+".") {
                return fmt.Errorf("primitive attribute %s cannot have sub-key in %s", name, k)
            }
        }
    }
    return nil
}

Type guard

func isLeafKey(key, attrName string, ty cty.Type) bool {
    aty, ok := ty.AttributeTypes()[attrName]
    if !ok {
        return false
    }
    return aty.IsPrimitiveType() && !strings.Contains(strings.TrimPrefix(key, attrName+"."), ".")
}

Prevention

When it happens

Trigger: Navigating a flatmap key like 'name.0' where the schema declares 'name' as a primitive cty.String. pathFromFlatmapKeyValue sees a non-empty rest segment while ty.IsPrimitiveType() is true, hitting the first case branch that returns this error.

Common situations: Schema changed a primitive attribute to a collection (or vice versa) so the flatmap key depth no longer matches. A diff/state key has extra dot-segments that imply nesting the schema doesn't support. Manually edited state introducing spurious sub-keys on a scalar.

Related errors


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