{"record":{"id":"222071d543d3b4ac","repo":"hashicorp/nomad","slug":"secret-q-has-provider-vault-but-no-vault-block","errorCode":null,"errorMessage":"Secret %q has provider \"vault\" but no vault block","messagePattern":"Secret %q has provider \"vault\" but no vault block","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/structs/structs.go","lineNumber":8453,"sourceCode":"\t\tif wid.Name == WorkloadIdentityDefaultName {\n\t\t\tmErr.Errors = append(mErr.Errors, fmt.Errorf(\"Duplicate default identities found\"))\n\t\t}\n\n\t\tif err := wid.Validate(); err != nil {\n\t\t\tmErr.Errors = append(mErr.Errors, fmt.Errorf(\"Identity %q is invalid: %w\", wid.Name, err))\n\t\t}\n\t}\n\n\tsecrets := make(map[string]bool)\n\tfor _, s := range t.Secrets {\n\t\tif _, ok := secrets[s.Name]; ok {\n\t\t\tmErr.Errors = append(mErr.Errors, fmt.Errorf(\"Duplicate secret %q found\", s.Name))\n\t\t} else {\n\t\t\tsecrets[s.Name] = true\n\t\t}\n\n\t\tif s.Provider == SecretProviderVault && t.Vault == nil {\n\t\t\tmErr.Errors = append(mErr.Errors, fmt.Errorf(\"Secret %q has provider \\\"vault\\\" but no vault block\", s.Name))\n\t\t}\n\n\t\tif err := s.Validate(); err != nil {\n\t\t\tmErr.Errors = append(mErr.Errors, fmt.Errorf(\"Secret %q is invalid: %w\", s.Name, err))\n\t\t}\n\t}\n\n\treturn mErr.ErrorOrNil()\n}\n\n// validateServices takes a task and validates the services within it are valid\n// and reference ports that exist.\nfunc validateServices(t *Task, tgNetworks Networks) error {\n\tvar mErr multierror.Error\n\n\t// Ensure that services don't ask for nonexistent ports and their names are\n\t// unique.\n\tservicePorts := make(map[string]map[string]struct{})","sourceCodeStart":8435,"sourceCodeEnd":8471,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/structs/structs.go#L8435-L8471","documentation":"A task secret whose provider is \"vault\" requires the task (or task group) to have a vault block so Nomad can obtain a Vault token; Task.Validate emits this error when s.Provider == SecretProviderVault and t.Vault == nil.","triggerScenarios":"Task defines secrets { name=..., provider = \"vault\", ... } but has no vault { } block anywhere in the job/group/task; job migrated to the secrets block syntax while the legacy vault integration block was removed.","commonSituations":"Migrating from legacy Vault stanza to the new secrets/provider model and dropping vault blocks; assuming a cluster-level Vault connection suffices (a per-job vault block is still required); partial template rendering that drops the vault block.","solutions":["Add a vault { } block (group or task level) to the job granting the needed policies","Change the secret's provider to a non-vault provider if Vault is not actually used","If the cluster uses workload identity-based Vault auth, ensure the vault block plus identity aud are configured per Nomad version docs"],"exampleFix":"// before\nsecrets {\n  name     = \"db_password\"\n  provider = \"vault\"\n  path     = \"kv/data/db\"\n}\n// after\nvault {}\nsecrets {\n  name     = \"db_password\"\n  provider = \"vault\"\n  path     = \"kv/data/db\"\n}","handlingStrategy":"validation","validationCode":"for _, s := range t.Secrets {\n    if s.Provider == \"vault\" && t.Vault == nil {\n        return fmt.Errorf(\"secret %q uses provider vault; add a vault block\", s.Name)\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always pair vault-provider secrets with a vault { } block in the job","When migrating off the legacy vault stanza, keep the vault block for secrets usage","Check group-level vault inheritance in the Nomad version you run"],"tags":["nomad","vault","secrets","validation"],"backgroundTag":"missing-required-block","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"}