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  int64

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Create the variable with a lock (nomad var put -lock or LockID set) before attempting lock renew/unlock operations.
  2. Set the LockID field explicitly when constructing lock requests in API clients.
  3. 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

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


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/84fa4dc787920141. Report an issue: GitHub.