hashicorp/terraform · error
: block schema is nil
Error message
%s%s: block schema is nil
What it means
During schema validation, an entry in the Block's BlockTypes map (nested block types) has a nil value. Every nested block type name must map to a non-nil *NestedBlock schema. This is analogous to the nil-attribute error but for nested block definitions — a developer registered a block type name but never populated its schema.
Solutions
- Audit the provider schema construction for the resource/data source in the error message.
- Ensure every key in BlockTypes maps to a fully populated *configschema.NestedBlock.
- Use conditional logic to omit keys entirely rather than setting nil values.
- Add unit tests that call InternalValidate() on every resource and data source schema.
Example fix
// before — nil nested block
BlockTypes: map[string]*NestedBlock{
"config": {Nesting: ListNesting, Block: Block{...}},
"settings": nil, // ← bug
}
// after — populate or omit
BlockTypes: map[string]*NestedBlock{
"config": {Nesting: ListNesting, Block: Block{...}},
"settings": {Nesting: SetNesting, Block: Block{...}},
} Defensive patterns
Strategy: validation
Validate before calling
// Provider developers: ensure no nil nested block values
func sanitizeBlockTypeMap(blocks map[string]*configschema.NestedBlock) map[string]*configschema.NestedBlock {
clean := make(map[string]*configschema.NestedBlock, len(blocks))
for k, v := range blocks {
if v == nil {
log.Printf("WARN: block type %q has nil schema, removing", k)
continue
}
clean[k] = v
}
return clean
}
// Unit test gate:
func TestNoNilBlockTypes(t *testing.T) {
if err := myResourceSchema().InternalValidate(); err != nil {
t.Fatal(err)
}
} Prevention
- Never add a key to BlockTypes without a fully populated *NestedBlock value.
- Use conditional omission rather than nil assignment.
- Gate every schema change behind an InternalValidate() unit test.
When it happens
Trigger: Block.BlockTypes map contains a key mapped to nil. Triggered when schema construction code adds a nested block type key without a corresponding *NestedBlock value — e.g., dynamic map population that leaves gaps, or a schema generator bug.
Common situations: Provider developer builds BlockTypes map conditionally and some paths leave nil entries. Schema code generation tool emits incomplete maps. Refactoring removed a NestedBlock definition but left the map key. Dynamic schema construction loops that skip certain entries.
Related errors
- : attribute schema is nil
- top-level block schema is nil
- : all attributes within computed blocks must also be…
- : name defined as both attribute and child block type
- : name may contain only lowercase letters, digits and…
AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11).
Data as JSON: /api/errors/76dd6b11beb13f5a.
Report an issue: GitHub.
Appendix: source
Thrown at internal/configs/configschema/internal_validate.go:51
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))
} else if !validName.MatchString(name) {
multiErr = errors.Join(multiErr, fmt.Errorf("%s%s: name may contain only lowercase letters, digits and underscores", prefix, name))
}
if !blockS.Deprecated && blockS.DeprecationMessage != "" {
multiErr = errors.Join(multiErr, fmt.Errorf("%s%s: DeprecationMessage must not be set when Deprecated is false", prefix, name))
}
if blockS.MinItems < 0 || blockS.MaxItems < 0 {
multiErr = errors.Join(multiErr, fmt.Errorf("%s%s: MinItems and MaxItems must both be greater than zero", prefix, name))
}
// any nested blocks within a computed block must also be computed
if b.Computed && !blockS.Computed {View on GitHub (pinned to d32a084675)