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
- Ensure the Block is allocated before validation: `schema := &configschema.Block{...}`.
- If nil is legitimately possible, guard before calling InternalValidate: `if schema != nil { ... }`.
- 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
- Always allocate schema literals with &configschema.Block{}; never leave a *Block as its zero (nil) value.
- Run InternalValidate in a table test covering every resource/data-source schema.
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
- %s%s: attribute schema is nil
- %s%s: block schema is nil
- top-level block: DeprecationMessage must not be set when Dep
- %s%s: all attributes within computed blocks must also be com
- %s%s: name defined as both attribute and child block type
AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07).
Data as JSON: /api/errors/dfd1bcfe8dbac7fd.
Report an issue: GitHub.