{"record":{"id":"84fa4dc787920141","repo":"hashicorp/nomad","slug":"missing-lock-id","errorCode":null,"errorMessage":"missing lock ID","messagePattern":"missing lock ID","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/structs/variables.go","lineNumber":73,"sourceCode":"\t// minVariableLockTTL and maxVariableLockTTL determine the range of valid durations for the\n\t// TTL on a lock.They come from the experience on Consul.\n\tminVariableLockTTL = 10 * time.Second\n\tmaxVariableLockTTL = 24 * time.Hour\n\n\t// defaultLockTTL is the default value used to maintain a lock before it needs to\n\t// be renewed. The actual value comes from the experience with Consul.\n\tdefaultLockTTL = 15 * time.Second\n\n\t// defaultLockDelay is the default a lock will be blocked after the TTL\n\t// went by without any renews. It is intended to prevent split brain situations.\n\t// The actual value comes from the experience with Consul.\n\tdefaultLockDelay = 15 * time.Second\n)\n\nvar (\n\terrNoPath             = errors.New(\"missing path\")\n\terrNoNamespace        = errors.New(\"missing namespace\")\n\terrNoLock             = errors.New(\"missing lock ID\")\n\terrWildCardNamespace  = errors.New(\"can not target wildcard (\\\"*\\\")namespace\")\n\terrQuotaExhausted     = errors.New(\"variables are limited to 64KiB in total size\")\n\terrNegativeDelayOrTTL = errors.New(\"Lock delay and TTL must be positive\")\n\terrInvalidTTL         = errors.New(\"TTL must be between 10 seconds and 24 hours\")\n)\n\n// VariableMetadata is the metadata envelope for a Variable, it is the list\n// object and is shared data between an VariableEncrypted and a\n// VariableDecrypted object.\ntype VariableMetadata struct {\n\tNamespace string\n\tPath      string\n\n\t// Lock represents a variable which is used for locking functionality.\n\tLock *VariableLock `json:\",omitempty\"`\n\n\tCreateIndex uint64\n\tCreateTime  int64","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/structs/variables.go#L55-L91","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nreq := &structs.VariablesRenewLockRequest{Path: \"path\"}\n// after\nreq := &structs.VariablesRenewLockRequest{Path: \"path\", LockID: existingLockID}","handlingStrategy":"validation","validationCode":"if req.LockID == \"\" {\n\treturn errors.New(\"lock operations require a LockID; read the variable first\")\n}","typeGuard":"func hasLock(v *structs.Variable) bool { return v != nil && v.LockID != \"\" }","tryCatchPattern":"if errors.Is(err, structs.ErrNoLock) {\n\t// fetch existing variable and reuse its LockID before retrying\n}","preventionTips":["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"],"tags":["nomad","variables","locking","validation"],"backgroundTag":"missing-required-argument","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}