hashicorp/terraform · error · LockError
invalid lock id
Error message
invalid lock id
What it means
In NestingList or NestingSet mode, Computed cannot be combined with MinItems > 0. A computed block is populated by the provider, so forcing the user to supply a minimum number of instances is contradictory. The validator rejects Computed blocks that also demand at least one element.
Solutions
- Set MinItems: 0 when the block is Computed.
- If a minimum count is mandatory, set Computed: false and let the user supply the instances.
Example fix
// before
"outputs": {
Nesting: configschema.NestingList,
MinItems: 1,
Block: configschema.Block{Computed: true},
},
// after
"outputs": {
Nesting: configschema.NestingList,
MinItems: 0,
Block: configschema.Block{Computed: true},
}, Defensive patterns
Strategy: validation
Validate before calling
// In NestingList/NestingSet, Computed forbids MinItems > 0.
func validListSetComputed(nb *configschema.NestedBlock) bool {
switch nb.Nesting {
case configschema.NestingList, configschema.NestingSet:
return !(nb.Computed && nb.MinItems > 0)
}
return true
} Type guard
func computedAllowsMin(computed bool, min int) bool { return !computed || min == 0 } Prevention
- When marking a list/set block Computed, set MinItems to 0.
- Do not require user-supplied instances on a provider-populated block.
- Validate with InternalValidate in provider unit tests.
When it happens
Trigger: NestingList/NestingSet with Computed: true and MinItems >= 1. Guard at internal_validate.go:107 is `blockS.MinItems > 0 && blockS.Computed`.
Common situations: Marking a previously-required block as Computed without zeroing MinItems; wanting provider-managed output but still requiring config input.
Related errors
- failed to append certs
- the state is already locked by another terraform client
- cannot delete default state
- consul lock was lost
- empty state name
AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11).
Data as JSON: /api/errors/9a56f6100ea77f87.
Report an issue: GitHub.
Appendix: source
Thrown at internal/backend/remote-state/inmem/backend.go:213
return info.ID, nil
}
func (l *lockMap) unlock(name, id string) error {
l.Lock()
defer l.Unlock()
lockInfo := l.m[name]
if lockInfo == nil {
return errors.New("state not locked")
}
lockErr := &statemgr.LockError{
Info: &statemgr.LockInfo{},
}
if id != lockInfo.ID {
lockErr.Err = errors.New("invalid lock id")
*lockErr.Info = *lockInfo
return lockErr
}
delete(l.m, name)
return nil
}
View on GitHub (pinned to d32a084675)