{"record":{"id":"938a8e9b43d1c487","repo":"hashicorp/nomad","slug":"locknopatherr","errorCode":"LockNoPathErr","errorMessage":"variable's path can't be empty","messagePattern":"variable's path can't be empty","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"api/locks.go","lineNumber":36,"sourceCode":"\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\t// ErrLockConflict is returned in case a lock operation can't be performed\n\t// because the caller is not the current holder of the lock.\n\tErrLockConflict = errors.New(\"conflicting operation over lock\")\n\n\t//LockNoPathErr is returned when no path is provided in the variable to be\n\t// used for the lease mechanism\n\tLockNoPathErr = errors.New(\"variable's path can't be empty\")\n)\n\n// Locks returns a new handle on a lock for the given variable.\nfunc (c *Client) Locks(wo WriteOptions, v Variable, opts ...LocksOption) (*Locks, error) {\n\n\tif v.Path == \"\" {\n\t\treturn nil, LockNoPathErr\n\t}\n\n\tttl, err := time.ParseDuration(v.Lock.TTL)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tl := &Locks{\n\t\tc:            c,\n\t\tWriteOptions: wo,\n\t\tvariable:     v,","sourceCodeStart":18,"sourceCodeEnd":54,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/api/locks.go#L18-L54","documentation":"Sentinel error LockNoPathErr returned when constructing a Lock whose Path field is empty. Nomad variables (and thus the locks built on them) are addressed by path, so an empty path leaves no key to lock.","triggerScenarios":"Calling c.Locks(wo, v, opts...) where v.Path == \"\", e.g. a Variable struct built from partial config or deserialized from a spec missing the path key.","commonSituations":"Config file with the lock variable declared but no 'path' attribute; programmatically constructed Variable structs where only the name was set; variable fetched by prefix/list instead of by path.","solutions":["Set the Variable's Path field before calling Locks, e.g. v.Path = \"nomad/jobs/myjob/lock\"","Validate the path in configuration parsing and fail with a clear message early","If the variable was loaded from a list result, refetch it by full path so Path is populated"],"exampleFix":"// before\nv := api.Variable{Name: \"lock\"}\nlock, err := c.Locks(wo, v)\n// after\nv := api.Variable{Name: \"lock\", Path: \"nomad/jobs/myjob/lock\"}\nif v.Path == \"\" {\n    return errors.New(\"lock variable path is required\")\n}\nlock, err := c.Locks(wo, v)","handlingStrategy":"validation","validationCode":"func lockVariableReady(v api.Variable) bool { return v.Path != \"\" }","typeGuard":null,"tryCatchPattern":"lock, err := c.Locks(wo, v)\nif errors.Is(err, api.LockNoPathErr) {\n    return fmt.Errorf(\"lock variable %q has no path set\", v.Name)\n}","preventionTips":["Always populate Variable.Path before creating locks","Validate path presence at config-parse time with a clear error","Don't build locks from list-results; refetch the variable by full path"],"tags":["go","nomad","lock","variables","missing-field","client-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"}