hashicorp/nomad · error

secret path cannot be empty

Error message

secret path cannot be empty

What it means

This error is returned by SecureVariableMessian/Variable validation (structs.go) when a secret/variable entry declares a provider but has an empty Path. Nomad requires every templated secret reference to name both a provider and a path within that provider; a missing path makes the reference unresolvable. It is appended to a multierror alongside other field-level validation failures, so it may appear with more errors at once.

Source

Thrown at nomad/structs/structs.go:10643

		return nil
	}

	var mErr multierror.Error

	if s.Name == "" {
		_ = multierror.Append(&mErr, errors.New("secret name cannot be empty"))
	}

	if !validSecretName.MatchString(s.Name) {
		_ = multierror.Append(&mErr, fmt.Errorf("secret name must match regex %s", validSecretName))
	}

	if s.Provider == "" {
		_ = multierror.Append(&mErr, errors.New("secret provider cannot be empty"))
	}

	if s.Path == "" {
		_ = multierror.Append(&mErr, errors.New("secret path cannot be empty"))
	}

	if s.Provider == "nomad" || s.Provider == "vault" {
		if len(s.Env) > 0 {
			_ = multierror.Append(&mErr, fmt.Errorf("%s provider cannot use the env block", s.Provider))
		}
	} else {
		if len(s.Config) > 0 {
			_ = multierror.Append(&mErr, fmt.Errorf("custom plugin provider %s cannot use the config block", s.Provider))
		}
	}

	return mErr.ErrorOrNil()
}

func (s *Secret) Canonicalize() {
	if s == nil {
		return

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Set the Path field on the secret/variable struct (or the path = "..." argument in the template/secret stanza) to the secret's location, e.g. "secret/data/myapp".
  2. If the secret is not needed, remove the whole secret block rather than leaving a provider with an empty path.
  3. Inspect the full multierror response for sibling errors (provider empty, env block misuse) and fix them in the same submit.

Example fix

// before
sec := &structs.SecureVariableMessian{Provider: "vault"}
// after
sec := &structs.SecureVariableMessian{Provider: "vault", Path: "secret/data/app/config"}
Defensive patterns

Strategy: validation

Validate before calling

func validSecret(s *structs.Variable) bool {
	return s != nil && s.Provider != "" && s.Path != ""
}
if !validSecret(sec) {
	return fmt.Errorf("secret requires provider and path")
}

Type guard

func hasPath(s interface{ GetPath() string }) bool { return s != nil && s.GetPath() != "" }

Prevention

When it happens

Trigger: Submitting a job, variable, or CSI/secret configuration where the block sets Provider (e.g. "vault" or "nomad") but leaves Path empty; calling Check/NewACL paths that validate a secret struct via its Validate() method with Path == "".

Common situations: Hand-written HCL/JSON job files with a template stanza referencing a secret but omitting the path argument; programmatically constructed structs in tests or tooling where only Provider was filled; copy-pasted configs where the path line was deleted.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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