hashicorp/nomad · error
Lock delay and TTL must be positive
Error message
Lock delay and TTL must be positive
What it means
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.
Source
Thrown at nomad/structs/variables.go:76
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
ModifyIndex uint64
ModifyTime int64
}View on GitHub (pinned to 482b49bf1a)
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.
Example fix
// before
lock := &structs.VariableLock{LockDelay: -5 * time.Second}
err := lock.Validate() // Lock delay and TTL must be positive
// after
lock := &structs.VariableLock{LockDelay: 5 * time.Second, TTL: 60 * time.Second}
err := lock.Validate() Defensive patterns
Strategy: validation
Validate before calling
func lockDurationsValid(lockDelay, ttl time.Duration) bool {
return lockDelay >= 0 && ttl >= 0
} Try / catch
if err := lock.Validate(); err != nil {
if strings.Contains(err.Error(), "must be positive") {
return fmt.Errorf("LockDelay/TTL must be >= 0, got LockDelay=%s TTL=%s", lock.LockDelay, lock.TTL)
}
return err
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- TTL must be between 10 seconds and 24 hours
- LockNoPathErr
- multiple lock operations
- Reschedule policy has unlimited attempts enabled and a low d
- missing path
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/f8727805a6dc01cd.
Report an issue: GitHub.