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

  1. Set MinItems: 0 when the block is Computed.
  2. 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 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


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)