{"record":{"id":"4ac2babbe4541be1","repo":"hashicorp/nomad","slug":"invalid-destination-path-v","errorCode":null,"errorMessage":"invalid destination path: %v","messagePattern":"invalid destination path: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/structs/structs.go","lineNumber":6149,"sourceCode":"type DispatchPayloadConfig struct {\n\t// File specifies a relative path to where the input data should be written\n\tFile string\n}\n\nfunc (d *DispatchPayloadConfig) Copy() *DispatchPayloadConfig {\n\tif d == nil {\n\t\treturn nil\n\t}\n\tnd := new(DispatchPayloadConfig)\n\t*nd = *d\n\treturn nd\n}\n\nfunc (d *DispatchPayloadConfig) Validate() error {\n\t// Verify the destination doesn't escape\n\tescaped, err := escapingfs.PathEscapesAllocViaRelative(\"task/local/\", d.File)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"invalid destination path: %v\", err)\n\t} else if escaped {\n\t\treturn fmt.Errorf(\"destination escapes allocation directory\")\n\t}\n\n\treturn nil\n}\n\nconst (\n\tTaskLifecycleHookPrestart  = \"prestart\"\n\tTaskLifecycleHookPoststart = \"poststart\"\n\tTaskLifecycleHookPoststop  = \"poststop\"\n)\n\ntype TaskLifecycleConfig struct {\n\tHook    string\n\tSidecar bool\n}\n","sourceCodeStart":6131,"sourceCodeEnd":6167,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/structs/structs.go#L6131-L6167","documentation":"DispatchPayloadConfig.Validate checks that the task-relative destination File path does not escape the allocation directory, using escapingfs.PathEscapesAllocViaRelative(\"task/local/\", d.File). If the path check itself errors, this wrapping error is returned; if the path escapes, a separate escape error is returned instead.","triggerScenarios":"Submitting a dispatch/parameterized job whose dispatch_payload block sets file to a path that cannot be safely evaluated relative to task/local/ — e.g. empty, containing invalid separators, or tripping the relative-path checker.","commonSituations":"Setting file to absolute paths like \"/etc/passwd\" or paths with .. segments; OS-specific path confusion (backslashes on Linux); path strings built programmatically with wrong joins.","solutions":["Set file to a simple relative path such as \"payload.txt\" — the payload lands under task/local/.","Remove any leading \"/\", drive letters, or .. segments from the file value.","Verify the value with PathEscapesAllocViaRelative (or filepath.Clean + prefix check) before submitting.","Run `nomad job validate` to confirm the corrected dispatch_payload block."],"exampleFix":"// before\ndispatch_payload {\n  file = \"/tmp/payload.json\"\n}\n// after\ndispatch_payload {\n  file = \"payload.json\"\n}","handlingStrategy":"validation","validationCode":"func safeDispatchFile(dest string) bool {\n    if dest == \"\" {\n        return false\n    }\n    clean := filepath.Clean(dest)\n    return !filepath.IsAbs(clean) && !strings.HasPrefix(clean, \"..\")\n}\n// call before submitting: if !safeDispatchFile(dp.File) { ... }","typeGuard":null,"tryCatchPattern":"if err := dp.Validate(); err != nil {\n    if strings.Contains(err.Error(), \"invalid destination path\") || strings.Contains(err.Error(), \"escapes\") {\n        // replace with a plain relative filename\n    }\n}","preventionTips":["Use simple relative filenames (\"payload.txt\") for dispatch_payload.file.","Never use absolute paths or \"..\" segments.","Normalize paths with filepath.Clean and reject anything containing \"..\".","Use forward slashes; avoid OS-specific separators in job specs."],"tags":["nomad","validation","path-traversal","dispatch"],"backgroundTag":"path-escapes-alloc-directory","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"}