hashicorp/nomad · error · ErrMultipleNamespaces

%w, Namespaces: %s

Error message

%w, Namespaces: %s

What it means

Nomad jobs may specify only one Vault cluster/namespace per job. This error is returned by the job Vault admission hook when the job declares Vault blocks spanning more than one namespace, listing the offending namespaces after the wrapped ErrMultipleNamespaces sentinel (check errors with errors.Is).

Source

Thrown at nomad/job_endpoint_hook_vault_ce.go:21

//go:build !ent

package nomad

import (
	"errors"
	"fmt"
	"strings"

	"github.com/hashicorp/nomad/nomad/structs"
)

// validateNamespaces returns an error if the job contains any Vault namespaces.
func (jobVaultHook) validateNamespaces(blocks map[string]map[string]*structs.Vault) error {

	requestedNamespaces := structs.VaultNamespaceSet(blocks)
	if len(requestedNamespaces) > 0 {
		return fmt.Errorf("%w, Namespaces: %s", ErrMultipleNamespaces, strings.Join(requestedNamespaces, ", "))
	}
	return nil
}

func (h jobVaultHook) validateClustersForNamespace(_ *structs.Job, blocks map[string]map[string]*structs.Vault) error {
	for _, tg := range blocks {
		for _, vault := range tg {
			if vault.Cluster != "default" {
				return errors.New("non-default Vault cluster requires Nomad Enterprise")
			}
		}
	}

	return nil
}

func (h jobVaultHook) Mutate(job *structs.Job) (*structs.Job, []error, error) {
	for _, tg := range job.TaskGroups {

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Set the same vault.namespace in every vault block across all task groups (or omit namespace to use the agent default)
  2. Move jobs needing different namespaces into separate job submissions
  3. Remove the vault namespace field entirely and rely on the Nomad agent's default Vault namespace

Example fix

// before
group "app" { vault { namespace = "team-a" } }
group "admin" { vault { namespace = "team-b" } }
// after
group "app" { vault { namespace = "team-a" } }
group "admin" { vault { namespace = "team-a" } }
Defensive patterns

Strategy: validation

Validate before calling

nss := structs.VaultNamespaceSet(job.ToVaultBlocks())
if len(nss) > 1 {
	return fmt.Errorf("job uses %d vault namespaces: %s", len(nss), strings.Join(nss, ", "))
}

Type guard

func singleVaultNamespace(blocks map[string]map[string]*structs.Vault) bool {
	return len(structs.VaultNamespaceSet(blocks)) <= 1
}

Prevention

When it happens

Trigger: Submitting (POST /v1/jobs or nomad job run) a job whose vault blocks, summed across all task groups via structs.VaultNamespaceSet, resolve to more than one distinct Vault namespace.

Common situations: Copy-pasting task group definitions from jobs that each used a different Vault namespace; teams migrating namespaces leaving one group pointing at the old one; templated job files with per-group vault namespace variables.

Related errors


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/90e9cd663797fec2. Report an issue: GitHub.