hashicorp/terraform · error
%s%s: name defined as both attribute and child block type
Error message
%s%s: name defined as both attribute and child block type
What it means
The same name is present in both b.Attributes and b.BlockTypes (checked at lines 55-56) - Terraform cannot decide whether that identifier is an attribute or a nested block, so it is rejected. Note this check runs before the name-format check (line 57) and is mutually exclusive with it via else-if.
Source
Thrown at internal/configs/configschema/internal_validate.go:56
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 {
multiErr = errors.Join(multiErr, fmt.Errorf("%s%s: all nested blocks within computed blocks must also be computed", prefix, name))
}
switch blockS.Nesting {
case NestingSingle:View on GitHub (pinned to c9def3e214)
Solutions
- Rename one of them so attribute and block-type names are disjoint.
- Remove the obsolete entry (e.g. delete the attribute when it became a block).
Example fix
// before
Attributes: map[string]*configschema.Attribute{ "rule": {Type: cty.String, Optional: true} }
BlockTypes: map[string]*configschema.NestedBlock{ "rule": {Nesting: configschema.NestingList} }
// after
Attributes: map[string]*configschema.Attribute{ "rule": {Type: cty.String, Optional: true} }
BlockTypes: map[string]*configschema.NestedBlock{ "rule_block": {Nesting: configschema.NestingList} } Defensive patterns
Strategy: validation
Validate before calling
for name := range block.BlockTypes {
if _, dup := block.Attributes[name]; dup {
return fmt.Errorf("name %q is both attribute and block", name)
}
} Prevention
- When composing schemas, de-duplicate names between Attributes and BlockTypes.
- Rename during attribute->block conversions rather than leaving both.
When it happens
Trigger: Defining `b.Attributes["foo"]` and `b.BlockTypes["foo"]` in the same Block, usually from merging two schema fragments or a copy-paste during an attribute->block conversion.
Common situations: Schema composition/inheritance, converting an attribute to a block without removing the old entry, generated schemas merging maps.
Related errors
- %s%s: name may contain only lowercase letters, digits and un
- top-level block schema is nil
- top-level block: DeprecationMessage must not be set when Dep
- %s%s: attribute schema is nil
- %s%s: all attributes within computed blocks must also be com
AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07).
Data as JSON: /api/errors/ca4b649001d38c1b.
Report an issue: GitHub.