{"record":{"id":"1693698478333752","repo":"hashicorp/packer","slug":"bad-script-s-s-169369","errorCode":null,"errorMessage":"Bad script '%s': %s","messagePattern":"Bad script '(.+?)': (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"provisioner/windows-shell/provisioner.go","lineNumber":123,"sourceCode":"\t\t\terrors.New(\"Only one of script or scripts can be specified.\"))\n\t}\n\n\tif p.config.Script != \"\" {\n\t\tp.config.Scripts = []string{p.config.Script}\n\t}\n\n\tif len(p.config.Scripts) == 0 && p.config.Inline == nil {\n\t\terrs = packersdk.MultiErrorAppend(errs,\n\t\t\terrors.New(\"Either a script file or inline script must be specified.\"))\n\t} else if len(p.config.Scripts) > 0 && p.config.Inline != nil {\n\t\terrs = packersdk.MultiErrorAppend(errs,\n\t\t\terrors.New(\"Only a script file or an inline script can be specified, not both.\"))\n\t}\n\n\tfor _, path := range p.config.Scripts {\n\t\tif _, err := os.Stat(path); err != nil {\n\t\t\terrs = packersdk.MultiErrorAppend(errs,\n\t\t\t\tfmt.Errorf(\"Bad script '%s': %s\", path, err))\n\t\t}\n\t}\n\n\t// Do a check for bad environment variables, such as '=foo', 'foobar'\n\tfor _, kv := range p.config.Vars {\n\t\tvs := strings.SplitN(kv, \"=\", 2)\n\t\tif len(vs) != 2 || vs[0] == \"\" {\n\t\t\terrs = packersdk.MultiErrorAppend(errs,\n\t\t\t\tfmt.Errorf(\"Environment variable not in format 'key=value': %s\", kv))\n\t\t}\n\t}\n\n\treturn errs\n}\n\n// This function takes the inline scripts, concatenates them\n// into a temporary file and returns a string containing the location\n// of said file.","sourceCodeStart":105,"sourceCodeEnd":141,"githubUrl":"https://github.com/hashicorp/packer/blob/eb36e3c3e48a036f3e8cc94087636ee72e1303c9/provisioner/windows-shell/provisioner.go#L105-L141","documentation":"Raised in the windows-shell provisioner's Prepare when a configured script file cannot be stat'ed on the host. Prepare validates each path in the 'scripts' array with os.Stat before the build runs; if a path is missing, unreadable, or is a directory, the provisioner appends this error so the build fails fast at validation time. The wrapped os error ('no such file or directory', 'permission denied', etc.) is included in the message.","triggerScenarios":"Calling Prepare (via `packer build` template validation) when any entry in the provisioner's `scripts` list points to a nonexistent file, a directory instead of a file, or a file the Packer process cannot access (os.Stat returns err) — windows-shell/provisioner.go:122-127.","commonSituations":"Typo or wrong relative path in the template ('scripts': [\"./scripts/setup.ps1\"] run from a different working directory); CI checkout missing the script (submodule not fetched); file deleted or renamed after the template was written; Windows path written with wrong separators/case on a Linux host.","solutions":["Correct the `scripts` path in the template so it points to an existing file relative to where `packer build` runs (use path.root in HCL2 to anchor paths).","Run `ls`/`test -f <path>` on the host to confirm the file exists and is readable before the build.","If both `scripts` and `inline` are intended, note this error path only covers scripts — but ensure you don't accidentally leave an empty/invalid scripts entry alongside inline.","Check file permissions if the path exists but the Packer user cannot stat/read it."],"exampleFix":"// before (HCL2): file does not exist relative to cwd\nprovisioner \"windows-shell\" {\n  scripts = [\"scripts/install.ps1\"]\n}\n// after: anchor to template directory\nprovisioner \"windows-shell\" {\n  scripts = [\"${path.root}/scripts/install.ps1\"]\n}","handlingStrategy":"validation","validationCode":"for _, s := range scripts {\n    info, err := os.Stat(s)\n    if err != nil { return fmt.Errorf(\"script %q missing: %w\", s, err) }\n    if info.IsDir() { return fmt.Errorf(\"script %q is a directory\", s) }\n}","typeGuard":null,"tryCatchPattern":"// Prepare fails the build before any infra is created; capture and report\nif err := run(\"packer\", \"validate\", tpl); err != nil {\n    if strings.Contains(errOutput, \"Bad script\") { fixScriptPaths(tpl) }\n}","preventionTips":["Anchor script paths with ${path.root} (HCL2) so they resolve regardless of cwd.","Run `packer validate` in CI before any build job.","Keep scripts in the repo and verify checkout/submodules in CI.","Never point `scripts` at directories; list files explicitly."],"tags":["provisioner","windows","validation","file-not-found"],"backgroundTag":"script-file-not-found","analyzedSha":"eb36e3c3e48a036f3e8cc94087636ee72e1303c9","analyzedAt":"2026-09-05T13:20:43.127Z","contentChangedAt":"2026-09-05T13:20:43.127Z","schemaVersion":2},"datasetVersion":"2026-09-12T17:17:11.597Z"}