hashicorp/terraform · error · LockError
state locked
Error message
state locked
What it means
A NestingSet block may not contain attributes whose type resolves to cty.DynamicPseudoType. The cty set implementation hashes elements by their concrete type, so it cannot store elements of unknown/mixed type. The validator computes the block's implied type and rejects it if any leaf is dynamic.
Solutions
- Replace cty.DynamicPseudoType with a concrete type (e.g. cty.String for JSON-in-string, or a defined object type).
- Switch the block from NestingSet to NestingList, which has no such constraint.
- Wrap dynamic payloads in a string-typed attribute holding serialized JSON.
Example fix
// before
"rules": {
Nesting: configschema.NestingSet,
Block: configschema.Block{Attributes: map[string]*configschema.Attribute{
"data": { Type: cty.DynamicPseudoType, Optional: true },
}},
},
// after
"rules": {
Nesting: configschema.NestingSet,
Block: configschema.Block{Attributes: map[string]*configschema.Attribute{
"data": { Type: cty.String, Optional: true }, // store JSON as string
}},
}, Defensive patterns
Strategy: validation
Validate before calling
// Reject NestingSet blocks whose implied type has dynamic leaves.
func setHasDynamic(nb *configschema.NestedBlock) bool {
if nb.Nesting != configschema.NestingSet { return false }
return nb.Block.ImpliedType().HasDynamicTypes()
} Type guard
// noDynamicTypes returns true when the block's implied type is free of cty.DynamicPseudoType.
func noDynamicTypes(b *configschema.Block) bool {
return !b.ImpliedType().HasDynamicTypes()
} Prevention
- Never use cty.DynamicPseudoType inside a NestingSet block.
- Use a concrete object type or cty.String for JSON payloads.
- Switch to NestingList if dynamic types are essential.
When it happens
Trigger: NestingSet block containing an attribute of type cty.DynamicPseudoType (directly or nested). Guard at internal_validate.go:94 is `ety := blockS.Block.ImpliedType(); ety.HasDynamicTypes()`.
Common situations: Using a free-form JSON attribute (cty.DynamicPseudoType) inside a set-valued block; migrating a NestingList with dynamic attrs to NestingSet.
Related errors
AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11).
Data as JSON: /api/errors/6f18d53146626f0e.
Report an issue: GitHub.
Appendix: source
Thrown at internal/backend/remote-state/inmem/backend.go:186
}
// Global level locks for inmem backends.
type lockMap struct {
sync.Mutex
m map[string]*statemgr.LockInfo
}
func (l *lockMap) lock(name string, info *statemgr.LockInfo) (string, error) {
l.Lock()
defer l.Unlock()
lockInfo := l.m[name]
if lockInfo != nil {
lockErr := &statemgr.LockError{
Info: lockInfo,
}
lockErr.Err = errors.New("state locked")
// make a copy of the lock info to avoid any testing shenanigans
*lockErr.Info = *lockInfo
return "", lockErr
}
info.Created = time.Now().UTC()
l.m[name] = info
return info.ID, nil
}
func (l *lockMap) unlock(name, id string) error {
l.Lock()
defer l.Unlock()
lockInfo := l.m[name]
if lockInfo == nil {View on GitHub (pinned to d32a084675)