{"record":{"id":"f8727805a6dc01cd","repo":"hashicorp/nomad","slug":"lock-delay-and-ttl-must-be-positive","errorCode":null,"errorMessage":"Lock delay and TTL must be positive","messagePattern":"Lock delay and TTL must be positive","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/structs/variables.go","lineNumber":76,"sourceCode":"\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\n\tModifyIndex uint64\n\tModifyTime  int64\n}","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/structs/variables.go#L58-L94","documentation":"VariableLock.Validate rejects a lock whose LockDelay or TTL is negative. Lock delay and time-to-live are durations and must be zero or positive; a negative value is treated as a configuration error and errNegativeDelayOrTTL is appended to the multierror. Nomad additionally enforces a positive-only TTL range via errInvalidTTL.","triggerScenarios":"Defining a VariableLock with LockDelay or TTL set to a negative time.Duration (e.g. -5 * time.Second) and calling Validate; also reproduced in TestStructs_Lock_Validate with LockDelay: -5 * time.Second.","commonSituations":"Hand-writing HCL/JSON lock config with a mistaken minus sign; templating durations from config where a negative default leaks in; unit tests intentionally checking invalid configs.","solutions":["Set LockDelay and TTL to non-negative durations (e.g. 5 * time.Second).","Clamp or validate user-supplied durations at config parse time before constructing VariableLock.","Remember TTL must additionally fall between minVariableLockTTL (10s) and maxVariableLockTTL (24h) to pass Validate."],"exampleFix":"// before\nlock := &structs.VariableLock{LockDelay: -5 * time.Second}\nerr := lock.Validate() // Lock delay and TTL must be positive\n// after\nlock := &structs.VariableLock{LockDelay: 5 * time.Second, TTL: 60 * time.Second}\nerr := lock.Validate()","handlingStrategy":"validation","validationCode":"func lockDurationsValid(lockDelay, ttl time.Duration) bool {\n\treturn lockDelay >= 0 && ttl >= 0\n}","typeGuard":null,"tryCatchPattern":"if err := lock.Validate(); err != nil {\n\tif strings.Contains(err.Error(), \"must be positive\") {\n\t\treturn fmt.Errorf(\"LockDelay/TTL must be >= 0, got LockDelay=%s TTL=%s\", lock.LockDelay, lock.TTL)\n\t}\n\treturn err\n}","preventionTips":["Never hand-write negative duration literals in lock configs.","Sanitize durations parsed from user config before constructing VariableLock.","Add a unit test covering negative LockDelay/TTL values."],"tags":["nomad","variables","lock","validation","configuration"],"backgroundTag":"invalid-config-value","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"}