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 all

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. List variables (nomad var list -namespace <ns>) to confirm the exact path and namespace before lock/release operations.
  2. Correct the path spelling and namespace in the client call.
  3. Treat not-found as success in unlock/purge cleanup code paths since the target state already holds.
  4. 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

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.