hashicorp/nomad · error
missing lock ID
Error message
missing lock ID
What it means
errNoLock is the sentinel error "missing lock ID" in Nomad's structs package. Lock-style variables (those with a LockID used for distributed locking) must carry a non-empty LockID; validation at variables.go:690 appends this error when v.LockID == "" so a lock request without an ID is rejected.
Source
Thrown at nomad/structs/variables.go:73
// minVariableLockTTL and maxVariableLockTTL determine the range of valid durations for the
// TTL on a lock.They come from the experience on Consul.
minVariableLockTTL = 10 * time.Second
maxVariableLockTTL = 24 * time.Hour
// defaultLockTTL is the default value used to maintain a lock before it needs to
// be renewed. The actual value comes from the experience with Consul.
defaultLockTTL = 15 * time.Second
// defaultLockDelay is the default a lock will be blocked after the TTL
// went by without any renews. It is intended to prevent split brain situations.
// The actual value comes from the experience with Consul.
defaultLockDelay = 15 * time.Second
)
var (
errNoPath = errors.New("missing path")
errNoNamespace = errors.New("missing namespace")
errNoLock = errors.New("missing lock ID")
errWildCardNamespace = errors.New("can not target wildcard (\"*\")namespace")
errQuotaExhausted = errors.New("variables are limited to 64KiB in total size")
errNegativeDelayOrTTL = errors.New("Lock delay and TTL must be positive")
errInvalidTTL = errors.New("TTL must be between 10 seconds and 24 hours")
)
// VariableMetadata is the metadata envelope for a Variable, it is the list
// object and is shared data between an VariableEncrypted and a
// VariableDecrypted object.
type VariableMetadata struct {
Namespace string
Path string
// Lock represents a variable which is used for locking functionality.
Lock *VariableLock `json:",omitempty"`
CreateIndex uint64
CreateTime int64View on GitHub (pinned to 482b49bf1a)
Solutions
- Create the variable with a lock (nomad var put -lock or LockID set) before attempting lock renew/unlock operations.
- Set the LockID field explicitly when constructing lock requests in API clients.
- Read the variable first and reuse its existing LockID rather than sending an empty one.
Example fix
// before
req := &structs.VariablesRenewLockRequest{Path: "path"}
// after
req := &structs.VariablesRenewLockRequest{Path: "path", LockID: existingLockID} Defensive patterns
Strategy: validation
Validate before calling
if req.LockID == "" {
return errors.New("lock operations require a LockID; read the variable first")
} Type guard
func hasLock(v *structs.Variable) bool { return v != nil && v.LockID != "" } Try / catch
if errors.Is(err, structs.ErrNoLock) {
// fetch existing variable and reuse its LockID before retrying
} Prevention
- Create lock variables with -lock / LockID set from the start
- Read the current variable to obtain its LockID before renew/unlock
- Never send empty LockID fields in lock API requests
When it happens
Trigger: Calling Variable.Validate or VariablesRenewLockRequest.Validate with LockID empty; performing lock/unlock or lock-renew operations on a variable that was not created with a lock ID; API payloads omitting the LockID key.
Common situations: Renewing a lock after the variable was written without lock semantics; automation that reads a variable and attempts lock operations assuming a LockID exists; tests like TestStructs_VariablesRenewLockRequest_Validate covering empty LockID.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- can not target wildcard ("*")namespace
- variable already holds a lock
- variable doesn't hold a lock
- missing path
- missing namespace
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/84fa4dc787920141.
Report an issue: GitHub.