{"record":{"id":"0cff62039c267803","repo":"hashicorp/nomad","slug":"could-not-find-destination-path-relative-to-chroot","errorCode":null,"errorMessage":"could not find destination path relative to chroot: %w","messagePattern":"could not find destination path relative to chroot: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/allocrunner/taskrunner/template/renderer/template_sandbox_default.go","lineNumber":32,"sourceCode":"\n// sandbox is the non-Windows sandbox implementation, which relies on chroot.\n// Although chroot is not an appropriate boundary for tasks (implicitly\n// untrusted), here the only code that's executing is Nomad itself. Returns the\n// new destPath inside the chroot.\nfunc sandbox(sandboxPath, destPath string) (string, error) {\n\n\terr := syscall.Chroot(sandboxPath)\n\tif err != nil {\n\t\t// if the user is running in unsupported non-root configuration, we\n\t\t// can't build the sandbox, but need to handle this gracefully\n\t\tfmt.Fprintf(os.Stderr, \"template-render sandbox %q not available: %v\",\n\t\t\tsandboxPath, err)\n\t\treturn destPath, nil\n\t}\n\n\tdestPath, err = filepath.Rel(sandboxPath, destPath)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"could not find destination path relative to chroot: %w\", err)\n\t}\n\tif !filepath.IsAbs(destPath) {\n\t\tdestPath = \"/\" + destPath\n\t}\n\n\treturn destPath, nil\n}\n","sourceCodeStart":14,"sourceCodeEnd":40,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/client/allocrunner/taskrunner/template/renderer/template_sandbox_default.go#L14-L40","documentation":"The template renderer's sandbox function chroots into the alloc dir (sandboxPath) and then computes the template's destination path relative to that chroot using filepath.Rel. filepath.Rel returns an error when the two paths cannot be made relative to each other — typically because destPath is not under sandboxPath, or the paths use incompatible forms (e.g. one relative, one absolute, or differing volume roots). The renderer returns this error and the template render fails.","triggerScenarios":"In sandbox(), syscall.Chroot succeeded, but filepath.Rel(sandboxPath, destPath) fails because the template's destination path is not contained within the sandbox/alloc-dir path — e.g. a template block with a destination outside the alloc dir, or mismatched relative/absolute path forms.","commonSituations":"Job template blocks using absolute destination paths that escape the alloc dir (e.g. destination = \"/etc/foo.conf\" while sandboxing is enforced); misconfigured client template options changing the sandbox path; symlinked or normalized alloc dir paths where lexical Rel cannot succeed; comparing a relative destPath against an absolute sandboxPath.","solutions":["Change the template's destination to a path inside the alloc dir (e.g. \"local/foo.conf\" or \"NOMAD_SECRETS_DIR/...\")","Use a relative destination path in the template block instead of an absolute host path","Check client template config (function_blacklist / disable_file_sandbox and sandbox settings) that affect sandboxPath","Ensure the alloc dir path has no symlinks or irregular normalization that breaks filepath.Rel; align both paths' forms","If writing outside the sandbox is truly required, evaluate whether sandboxing can be disabled for that client per security policy"],"exampleFix":"// before: template destination outside the alloc dir sandbox\ntemplate {\n  data        = \"...\"\n  destination = \"/etc/app/config.conf\"\n}\n\n// after: destination inside the alloc dir\ntemplate {\n  data        = \"...\"\n  destination = \"local/config.conf\"\n}","handlingStrategy":"validation","validationCode":"// Validate template destinations before submitting the job\nfunc validTemplateDest(dest string) bool {\n    if filepath.IsAbs(dest) {\n        return false // must be alloc-dir relative, e.g. \"local/app.conf\"\n    }\n    cleaned := filepath.Clean(dest)\n    return !strings.HasPrefix(cleaned, \"..\") && !filepath.IsAbs(cleaned)\n}\n// for each template block: if !validTemplateDest(t.Destination) { return err }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always use alloc-dir-relative destinations (local/, secrets/) in template blocks","Run nomad job validate / plan before submitting jobs with template stanzas","Avoid symlinks in alloc_dir that could break lexical path relativization","Review client template sandbox settings when changing Nomad versions"],"tags":["nomad","template","renderer","sandbox","path"],"backgroundTag":"path-escape-sandbox","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"}