{"record":{"id":"db48c688e1a833c0","repo":"hashicorp/nomad","slug":"secret-path-cannot-be-empty","errorCode":null,"errorMessage":"secret path cannot be empty","messagePattern":"secret path cannot be empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/structs/structs.go","lineNumber":10643,"sourceCode":"\t\treturn nil\n\t}\n\n\tvar mErr multierror.Error\n\n\tif s.Name == \"\" {\n\t\t_ = multierror.Append(&mErr, errors.New(\"secret name cannot be empty\"))\n\t}\n\n\tif !validSecretName.MatchString(s.Name) {\n\t\t_ = multierror.Append(&mErr, fmt.Errorf(\"secret name must match regex %s\", validSecretName))\n\t}\n\n\tif s.Provider == \"\" {\n\t\t_ = multierror.Append(&mErr, errors.New(\"secret provider cannot be empty\"))\n\t}\n\n\tif s.Path == \"\" {\n\t\t_ = multierror.Append(&mErr, errors.New(\"secret path cannot be empty\"))\n\t}\n\n\tif s.Provider == \"nomad\" || s.Provider == \"vault\" {\n\t\tif len(s.Env) > 0 {\n\t\t\t_ = multierror.Append(&mErr, fmt.Errorf(\"%s provider cannot use the env block\", s.Provider))\n\t\t}\n\t} else {\n\t\tif len(s.Config) > 0 {\n\t\t\t_ = multierror.Append(&mErr, fmt.Errorf(\"custom plugin provider %s cannot use the config block\", s.Provider))\n\t\t}\n\t}\n\n\treturn mErr.ErrorOrNil()\n}\n\nfunc (s *Secret) Canonicalize() {\n\tif s == nil {\n\t\treturn","sourceCodeStart":10625,"sourceCodeEnd":10661,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/structs/structs.go#L10625-L10661","documentation":"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.","triggerScenarios":"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 == \"\".","commonSituations":"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.","solutions":["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\".","If the secret is not needed, remove the whole secret block rather than leaving a provider with an empty path.","Inspect the full multierror response for sibling errors (provider empty, env block misuse) and fix them in the same submit."],"exampleFix":"// before\nsec := &structs.SecureVariableMessian{Provider: \"vault\"}\n// after\nsec := &structs.SecureVariableMessian{Provider: \"vault\", Path: \"secret/data/app/config\"}","handlingStrategy":"validation","validationCode":"func validSecret(s *structs.Variable) bool {\n\treturn s != nil && s.Provider != \"\" && s.Path != \"\"\n}\nif !validSecret(sec) {\n\treturn fmt.Errorf(\"secret requires provider and path\")\n}","typeGuard":"func hasPath(s interface{ GetPath() string }) bool { return s != nil && s.GetPath() != \"\" }","tryCatchPattern":null,"preventionTips":["Always pair provider with path in secret/variable stanzas","Run `nomad job validate` before submitting jobs","Check the full multierror list, not just the first message"],"tags":["nomad","validation","secrets","config"],"backgroundTag":"missing-required-argument","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"}