{"record":{"id":"90e9cd663797fec2","repo":"hashicorp/nomad","slug":"w-namespaces-s","errorCode":null,"errorMessage":"%w, Namespaces: %s","messagePattern":"%w, Namespaces: (.+?)","errorType":"validation","errorClass":"ErrMultipleNamespaces","httpStatus":null,"severity":"error","filePath":"nomad/job_endpoint_hook_vault_ce.go","lineNumber":21,"sourceCode":"\n//go:build !ent\n\npackage nomad\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/hashicorp/nomad/nomad/structs\"\n)\n\n// validateNamespaces returns an error if the job contains any Vault namespaces.\nfunc (jobVaultHook) validateNamespaces(blocks map[string]map[string]*structs.Vault) error {\n\n\trequestedNamespaces := structs.VaultNamespaceSet(blocks)\n\tif len(requestedNamespaces) > 0 {\n\t\treturn fmt.Errorf(\"%w, Namespaces: %s\", ErrMultipleNamespaces, strings.Join(requestedNamespaces, \", \"))\n\t}\n\treturn nil\n}\n\nfunc (h jobVaultHook) validateClustersForNamespace(_ *structs.Job, blocks map[string]map[string]*structs.Vault) error {\n\tfor _, tg := range blocks {\n\t\tfor _, vault := range tg {\n\t\t\tif vault.Cluster != \"default\" {\n\t\t\t\treturn errors.New(\"non-default Vault cluster requires Nomad Enterprise\")\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (h jobVaultHook) Mutate(job *structs.Job) (*structs.Job, []error, error) {\n\tfor _, tg := range job.TaskGroups {","sourceCodeStart":3,"sourceCodeEnd":39,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/job_endpoint_hook_vault_ce.go#L3-L39","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","solutions":["Set the same vault.namespace in every vault block across all task groups (or omit namespace to use the agent default)","Move jobs needing different namespaces into separate job submissions","Remove the vault namespace field entirely and rely on the Nomad agent's default Vault namespace"],"exampleFix":"// before\ngroup \"app\" { vault { namespace = \"team-a\" } }\ngroup \"admin\" { vault { namespace = \"team-b\" } }\n// after\ngroup \"app\" { vault { namespace = \"team-a\" } }\ngroup \"admin\" { vault { namespace = \"team-a\" } }","handlingStrategy":"validation","validationCode":"nss := structs.VaultNamespaceSet(job.ToVaultBlocks())\nif len(nss) > 1 {\n\treturn fmt.Errorf(\"job uses %d vault namespaces: %s\", len(nss), strings.Join(nss, \", \"))\n}","typeGuard":"func singleVaultNamespace(blocks map[string]map[string]*structs.Vault) bool {\n\treturn len(structs.VaultNamespaceSet(blocks)) <= 1\n}","tryCatchPattern":null,"preventionTips":["Standardize one vault namespace per job in your templates","Lint job specs for multiple distinct vault.namespace values before submit","Get the namespace from a single variable rather than per-group literals"],"tags":["nomad","vault","validation","job-spec"],"backgroundTag":"vault-multiple-namespaces","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"}