hashicorp/terraform · error
%s%s: name may contain only lowercase letters, digits and un
Error message
%s%s: name may contain only lowercase letters, digits and underscores
What it means
A nested-block type name fails the validName regex `^[a-z0-9_]+$` (checked at line 57): it contains uppercase letters, hyphens, dots, or other characters. Terraform identifiers for block types must be lowercase snake_case. The identical check is commented out for attributes (see the FIXME at lines 141-145) but IS enforced for block types.
Source
Thrown at internal/configs/configschema/internal_validate.go:58
}
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:
switch {
case blockS.MinItems != blockS.MaxItems:View on GitHub (pinned to c9def3e214)
Solutions
- Rename the block type to lowercase snake_case: `myBlock` -> `my_block`.
- If generating schemas, add a normalization pass that lowercases and replaces separators with underscores.
Example fix
// before
BlockTypes: map[string]*configschema.NestedBlock{ "subnetConfig": {Nesting: configschema.NestingList} }
// after
BlockTypes: map[string]*configschema.NestedBlock{ "subnet_config": {Nesting: configschema.NestingList} } Defensive patterns
Strategy: validation
Validate before calling
var validName = regexp.MustCompile(`^[a-z0-9_]+$`)
for name := range block.BlockTypes {
if !validName.MatchString(name) { return fmt.Errorf("invalid block name %q", name) }
} Prevention
- Use lowercase snake_case for all block type names.
- Gate generated schemas with a normalization pass (lowercase + replace separators with _).
When it happens
Trigger: Naming a nested block `myBlock`, `my-block`, or `MyBlock` in a schema literal; generated schemas emitting camelCase names from an API spec.
Common situations: Copying JSON/YAML field names into Go schema literals, SDK generation from a spec using camelCase, mixing naming conventions.
Related errors
- %s%s: name defined as both attribute and child block type
- 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/c10018c3f8fb558e.
Report an issue: GitHub.