hashicorp/terraform · error

Failed to marshal index step key %#v: %s

Error message

Failed to marshal index step key %#v: %s

What it means

In encodePath, ctyjson.Marshal(s.Key, s.Key.Type()) for a cty.IndexStep key failed. The index key is a cty.Value; this error means its type cannot be serialized to JSON, so the path cannot be encoded losslessly.

Source

Thrown at internal/command/jsonplan/plan.go:1072

	for _, path := range pathList {
		jsonPath, err := encodePath(path)
		if err != nil {
			return nil, err
		}
		jsonPaths = append(jsonPaths, jsonPath)
	}

	return json.Marshal(jsonPaths)
}

func encodePath(path cty.Path) (json.RawMessage, error) {
	steps := make([]json.RawMessage, 0, len(path))
	for _, step := range path {
		switch s := step.(type) {
		case cty.IndexStep:
			key, err := ctyjson.Marshal(s.Key, s.Key.Type())
			if err != nil {
				return nil, fmt.Errorf("Failed to marshal index step key %#v: %s", s.Key, err)
			}
			steps = append(steps, key)
		case cty.GetAttrStep:
			name, err := json.Marshal(s.Name)
			if err != nil {
				return nil, fmt.Errorf("Failed to marshal get attr step name %#v: %s", s.Name, err)
			}
			steps = append(steps, name)
		default:
			return nil, fmt.Errorf("Unsupported path step %#v (%t)", step, step)
		}
	}
	return json.Marshal(steps)
}

View on GitHub (pinned to c9def3e214)

Solutions

  1. Inspect the key shown via %#v to learn its type.
  2. Avoid relying on that attribute path in replace detection if possible.
  3. Report as a renderer bug if it occurs on a common/primitive key type.
Defensive patterns

Strategy: try-catch

Validate before calling

// Validate that every IndexStep key in recorded paths is JSON-serializable
// before marshaling, so failures surface with context.
for _, ra := range plan.RelevantAttributes {
    for _, step := range ra.Attr {
        if idx, ok := step.(cty.IndexStep); ok {
            if _, err := ctyjson.Marshal(idx.Key, idx.Key.Type()); err != nil {
                return fmt.Errorf("unserializable index key %#v in relevant attribute path: %w", idx.Key, err)
            }
        }
    }
}

Type guard

func serializablePathStep(step cty.PathStep) error {
    switch s := step.(type) {
    case cty.IndexStep:
        _, err := ctyjson.Marshal(s.Key, s.Key.Type())
        return err
    case cty.GetAttrStep:
        return nil // string name; validated separately
    default:
        return fmt.Errorf("unsupported step %T", step)
    }
}

Try / catch

out, err := jsonplan.Marshal(config, plan, sf, schemas)
if err != nil && strings.Contains(err.Error(), "marshal index step key") {
    // a path index key is not JSON-serializable; capture the %#v value for triage
}
return err

Prevention

When it happens

Trigger: A relevant-attribute or replace path includes an IndexStep whose key is of a non-JSON-serializable type (e.g. a complex object used as a set element key). Reached via encodePaths/encodePath from relevant attributes (607) or replace_paths encoding.

Common situations: Paths into set-typed attributes where elements are keyed by a structured type; an internal type-handling gap for an unusual attribute type; rarely, a corrupted path.

Related errors


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