hashicorp/terraform · error

top-level block schema is nil

Error message

top-level block schema is nil

What it means

InternalValidate returns this when the receiver Block pointer itself is nil. It is the first guard in Block.InternalValidate() (line 23): a nil top-level schema has nothing to validate, so it fails immediately. This is a provider/schema-author programming error, surfaced in unit tests or during schema loading in NewContext.

Source

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

import (
	"errors"
	"fmt"
	"regexp"

	"github.com/zclconf/go-cty/cty"
)

var validName = regexp.MustCompile(`^[a-z0-9_]+$`)

// InternalValidate returns an error if the receiving block and its child schema
// definitions have any inconsistencies with the documented rules for valid
// schema.
//
// 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))

View on GitHub (pinned to c9def3e214)

Solutions

  1. Ensure the Block is allocated before validation: `schema := &configschema.Block{...}`.
  2. If nil is legitimately possible, guard before calling InternalValidate: `if schema != nil { ... }`.
  3. Add a unit test that calls InternalValidate on every exported schema so this is caught in CI.

Example fix

// before
var schema *configschema.Block
if err := schema.InternalValidate(); err != nil { t.Fatal(err) }

// after
schema := &configschema.Block{
    Attributes: map[string]*configschema.Attribute{
        "name": {Type: cty.String, Optional: true, Computed: true},
    },
}
if err := schema.InternalValidate(); err != nil { t.Fatal(err) }
Defensive patterns

Strategy: type-guard

Type guard

// Guard against a nil schema before validating.
func schemaValid(b *configschema.Block) error {
    if b == nil { return errors.New("schema Block must be non-nil") }
    return b.InternalValidate()
}

Prevention

When it happens

Trigger: Calling (*Block)(nil).InternalValidate(), or a schema map field pointing to an uninitialized *Block. Typically a missing return/initialization in provider GetSchemaResponse, or a test that declares `var schema *configschema.Block` and validates it.

Common situations: New resource/data-source schema left nil, a refactor that returns nil before assigning the schema, schema tables built conditionally where a branch returns nil.

Related errors


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