hashicorp/nomad · error

Secret %q has provider "vault" but no vault block

Error message

Secret %q has provider "vault" but no vault block

What it means

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.

Source

Thrown at nomad/structs/structs.go:8453

		if wid.Name == WorkloadIdentityDefaultName {
			mErr.Errors = append(mErr.Errors, fmt.Errorf("Duplicate default identities found"))
		}

		if err := wid.Validate(); err != nil {
			mErr.Errors = append(mErr.Errors, fmt.Errorf("Identity %q is invalid: %w", wid.Name, err))
		}
	}

	secrets := make(map[string]bool)
	for _, s := range t.Secrets {
		if _, ok := secrets[s.Name]; ok {
			mErr.Errors = append(mErr.Errors, fmt.Errorf("Duplicate secret %q found", s.Name))
		} else {
			secrets[s.Name] = true
		}

		if s.Provider == SecretProviderVault && t.Vault == nil {
			mErr.Errors = append(mErr.Errors, fmt.Errorf("Secret %q has provider \"vault\" but no vault block", s.Name))
		}

		if err := s.Validate(); err != nil {
			mErr.Errors = append(mErr.Errors, fmt.Errorf("Secret %q is invalid: %w", s.Name, err))
		}
	}

	return mErr.ErrorOrNil()
}

// validateServices takes a task and validates the services within it are valid
// and reference ports that exist.
func validateServices(t *Task, tgNetworks Networks) error {
	var mErr multierror.Error

	// Ensure that services don't ask for nonexistent ports and their names are
	// unique.
	servicePorts := make(map[string]map[string]struct{})

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Add a vault { } block (group or task level) to the job granting the needed policies
  2. Change the secret's provider to a non-vault provider if Vault is not actually used
  3. If the cluster uses workload identity-based Vault auth, ensure the vault block plus identity aud are configured per Nomad version docs

Example fix

// before
secrets {
  name     = "db_password"
  provider = "vault"
  path     = "kv/data/db"
}
// after
vault {}
secrets {
  name     = "db_password"
  provider = "vault"
  path     = "kv/data/db"
}
Defensive patterns

Strategy: validation

Validate before calling

for _, s := range t.Secrets {
    if s.Provider == "vault" && t.Vault == nil {
        return fmt.Errorf("secret %q uses provider vault; add a vault block", s.Name)
    }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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