hashicorp/nomad · error
variable doesn't exist
Error message
variable doesn't exist
What it means
errVarNotFound is the sentinel for variable path lookups that miss in the state store. It is returned by operations such as VarLockRelease and RenewLock when the variable record (VariableEncrypted) for the given path cannot be found, and by the write path (state_store_variables.go:537) when an operation targets a nonexistent variable. Callers map it to a 404-class RPC error.
Source
Thrown at nomad/state/state_store_variables.go:17
// Copyright IBM Corp. 2015, 2026
// SPDX-License-Identifier: BUSL-1.1
package state
import (
"errors"
"fmt"
"math"
"github.com/hashicorp/go-memdb"
"github.com/hashicorp/nomad/nomad/structs"
)
var (
errVarAlreadyLocked = errors.New("variable already holds a lock")
errVarNotFound = errors.New("variable doesn't exist")
errLockNotFound = errors.New("variable doesn't hold a lock")
)
// Variables queries all the variables and is used only for
// snapshot/restore and key rotation
func (s *StateStore) Variables(ws memdb.WatchSet) (memdb.ResultIterator, error) {
txn := s.db.ReadTxn()
iter, err := txn.Get(TableVariables, indexID)
if err != nil {
return nil, err
}
ws.Add(iter.WatchCh())
return iter, nil
}
// GetVariablesByNamespace returns an iterator that contains allView on GitHub (pinned to 482b49bf1a)
Solutions
- List variables (nomad var list -namespace <ns>) to confirm the exact path and namespace before lock/release operations.
- Correct the path spelling and namespace in the client call.
- Treat not-found as success in unlock/purge cleanup code paths since the target state already holds.
- Re-create the variable if it was deleted unintentionally (nomad var put).
Example fix
// before: renew on a wrong path
_, err := client.Variables().RenewLock("secret/app/db", writeOpts)
// after: verify existence first
_, _, err := client.Variables().Read("secret/app/db", nil)
if err != nil { return fmt.Errorf("variable missing: %w", err) }
_, err = client.Variables().RenewLock("secret/app/db", writeOpts) Defensive patterns
Strategy: validation
Validate before calling
// confirm the variable path and namespace before lock/release ops
_, _, err := client.Variables().Read(path, &api.QueryOptions{Namespace: ns})
if err != nil {
return fmt.Errorf("variable %s/%s does not exist", ns, path)
} Try / catch
_, err := client.Variables().RenewLock(path, writeOpts)
if err != nil && strings.Contains(err.Error(), "doesn't exist") {
return nil // treat as already-purged for cleanup paths
} Prevention
- Build paths from constants/templates, not string concatenation of user input.
- Always scope variable operations with the right namespace.
- List variables (`nomad var list`) to verify paths in interactive use.
- Handle concurrent deletion between read and lock/release gracefully.
When it happens
Trigger: nomad var unlock/purge or lock renewal (RenewLock) on a path that has no stored variable; test table lookUpPath "fake/path/" style misses; using a path with wrong namespace; the variable was deleted concurrently between listing and acting on it.
Common situations: Typos in variable paths (paths are hierarchical keys like secret/app/config); wrong -namespace since variables are namespace-scoped; scripts unlocking variables that were already purged; expired variables removed by GC between calls.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/b1a4e33f6f61a0f4.
Report an issue: GitHub.