{"record":{"id":"e2c6ed0e3fd99c6c","repo":"hashicorp/nomad","slug":"must-specify-a-source-path-or-have-an-embedded-tem","errorCode":null,"errorMessage":"Must specify a source path or have an embedded template","messagePattern":"Must specify a source path or have an embedded template","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/structs/structs.go","lineNumber":8964,"sourceCode":"\n\tnt.ChangeScript = t.ChangeScript.Copy()\n\tnt.Wait = t.Wait.Copy()\n\n\treturn nt\n}\n\nfunc (t *Template) Canonicalize() {\n\tif t.ChangeSignal != \"\" {\n\t\tt.ChangeSignal = strings.ToUpper(t.ChangeSignal)\n\t}\n}\n\nfunc (t *Template) Validate() error {\n\tvar mErr multierror.Error\n\n\t// Verify we have something to render\n\tif t.SourcePath == \"\" && t.EmbeddedTmpl == \"\" {\n\t\t_ = multierror.Append(&mErr, fmt.Errorf(\"Must specify a source path or have an embedded template\"))\n\t}\n\n\t// Verify we can render somewhere\n\tif t.DestPath == \"\" {\n\t\t_ = multierror.Append(&mErr, fmt.Errorf(\"Must specify a destination for the template\"))\n\t}\n\n\t// Verify the destination doesn't escape\n\tescaped, err := escapingfs.PathEscapesAllocViaRelative(\"task\", t.DestPath)\n\tif err != nil {\n\t\tmErr.Errors = append(mErr.Errors, fmt.Errorf(\"invalid destination path: %v\", err))\n\t} else if escaped {\n\t\tmErr.Errors = append(mErr.Errors, fmt.Errorf(\"destination escapes allocation directory\"))\n\t}\n\n\t// Verify a proper change mode\n\tswitch t.ChangeMode {\n\tcase TemplateChangeModeNoop, TemplateChangeModeRestart:","sourceCodeStart":8946,"sourceCodeEnd":8982,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/structs/structs.go#L8946-L8982","documentation":"Template.Validate() requires that a template stanza has renderable content: either a `source` path (SourcePath) or inline `data`/`embedded template` (EmbeddedTmpl). If both are empty there is nothing to render, so validation fails and the error is appended to the template's multierror.","triggerScenarios":"Submitting a job with an empty `template {}` stanza — no `source`, no `data`, no `destination`. Thrown whenever t.SourcePath == \"\" && t.EmbeddedTmpl == \"\" during job validation.","commonSituations":"HCL templating accident where `source`/`data` were dropped or indented into a nested block; generating job specs programmatically and leaving the template fields blank; converting from another orchestrator format and forgetting the content field.","solutions":["Add inline content via the `data` field: template { data = \"...\" destination = \"...\" }.","Or point to a file: template { source = \"tpl/nginx.conf.tpl\" destination = \"...\" }.","Check HCL indentation/nesting so the template stanza actually captures source/data."],"exampleFix":"// before\ntemplate {\n  destination = \"local/config.yml\"\n}\n// after\ntemplate {\n  data        = \"key: value\"\n  destination = \"local/config.yml\"\n}","handlingStrategy":"validation","validationCode":"// Pre-submit check\nif tpl.Source == \"\" && tpl.Data == \"\" {\n  return errors.New(\"template needs source or data\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always pair a template destination with source or data.","Check HCL nesting so fields land in the right stanza.","Run `nomad job validate` before every apply."],"tags":["nomad","template","job-spec-validation"],"backgroundTag":"missing-template-source","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"}