hashicorp/terraform · error

: attribute schema is nil

Error message

%s%s: attribute schema is nil

What it means

During schema validation, an entry in the Block's Attributes map has a nil value. Every attribute name must map to a non-nil *Attribute schema. A nil attribute pointer indicates a programming error in schema construction — a developer added an attribute key but never populated its schema definition.

Solutions

  1. Audit the provider's schema construction code for the resource or data source named in the error.
  2. Ensure every key in the Attributes map maps to a fully populated *configschema.Attribute (or schema.Attribute in the framework).
  3. If using conditional attribute inclusion, use a filter step that removes keys entirely rather than setting them to nil.
  4. Add unit tests calling InternalValidate() on the schema to catch this before release.

Example fix

// before — nil attribute value in map
Attributes: map[string]*Attribute{
    "name":  {Type: String, Optional: true},
    "size":  nil,  // ← bug
}

// after — all attributes populated or omitted
Attributes: map[string]*Attribute{
    "name": {Type: String, Optional: true},
    "size": {Type: Int, Optional: true},
}
Defensive patterns

Strategy: validation

Validate before calling

// Provider developers: ensure no nil attribute values in schema
func sanitizeAttributeMap(attrs map[string]*configschema.Attribute) map[string]*configschema.Attribute {
    clean := make(map[string]*configschema.Attribute, len(attrs))
    for k, v := range attrs {
        if v == nil {
            log.Printf("WARN: attribute %q has nil schema, removing", k)
            continue
        }
        clean[k] = v
    }
    return clean
}

// Unit test gate:
func TestNoNilAttributes(t *testing.T) {
    if err := myResourceSchema().InternalValidate(); err != nil {
        t.Fatal(err)
    }
}

Prevention

When it happens

Trigger: Block.Attributes map contains a key mapped to nil. Triggered when a provider (or Terraform internal code) constructs a schema with an incompletely initialized Attributes map — e.g., assigning attributes["foo"] = nil instead of a populated *Attribute struct.

Common situations: Provider developer uses a map literal or loop that conditionally leaves entries nil. Schema generation tool produces incomplete output. terraform-plugin-sdk/schema-to-framework migration left gaps. Code path that adds attribute keys dynamically but skips some values.

Related errors


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

Appendix: source

Thrown at internal/configs/configschema/internal_validate.go:38

// This can be used within unit tests to detect when a given schema is invalid,
// and is run when terraform loads provider schemas during NewContext.
func (b *Block) InternalValidate() error {
	if b == nil {
		return fmt.Errorf("top-level block schema is nil")
	}
	return b.internalValidate("")
}

func (b *Block) internalValidate(prefix string) error {
	var multiErr error

	if prefix == "" && !b.Deprecated && b.DeprecationMessage != "" {
		multiErr = errors.Join(multiErr, fmt.Errorf("top-level block: DeprecationMessage must not be set when Deprecated is false"))
	}

	for name, attrS := range b.Attributes {
		if attrS == nil {
			multiErr = errors.Join(multiErr, fmt.Errorf("%s%s: attribute schema is nil", prefix, name))
			continue
		}
		multiErr = errors.Join(multiErr, attrS.internalValidate(name, prefix))

		// all attributes within a computed block must also be computed
		if b.Computed && !attrS.Computed {
			multiErr = errors.Join(multiErr, fmt.Errorf("%s%s: all attributes within computed blocks must also be computed", prefix, name))
		}
	}

	for name, blockS := range b.BlockTypes {
		if blockS == nil {
			multiErr = errors.Join(multiErr, fmt.Errorf("%s%s: block schema is nil", prefix, name))
			continue
		}

		if _, isAttr := b.Attributes[name]; isAttr {
			multiErr = errors.Join(multiErr, fmt.Errorf("%s%s: name defined as both attribute and child block type", prefix, name))

View on GitHub (pinned to d32a084675)