{"record":{"id":"61a6b14117fccacf","repo":"hashicorp/packer","slug":"only-one-of-script-or-scripts-can-be-specified-61a6b1","errorCode":null,"errorMessage":"Only one of script or scripts can be specified.","messagePattern":"Only one of script or scripts can be specified\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"provisioner/windows-shell/provisioner.go","lineNumber":105,"sourceCode":"\t\tp.config.StartRetryTimeout = 5 * time.Minute\n\t}\n\n\tif p.config.RemotePath == \"\" {\n\t\tp.config.RemotePath = DefaultRemotePath\n\t}\n\n\tif p.config.Scripts == nil {\n\t\tp.config.Scripts = make([]string, 0)\n\t}\n\n\tif p.config.Vars == nil {\n\t\tp.config.Vars = make([]string, 0)\n\t}\n\n\tvar errs error\n\tif p.config.Script != \"\" && len(p.config.Scripts) > 0 {\n\t\terrs = packersdk.MultiErrorAppend(errs,\n\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))","sourceCodeStart":87,"sourceCodeEnd":123,"githubUrl":"https://github.com/hashicorp/packer/blob/eb36e3c3e48a036f3e8cc94087636ee72e1303c9/provisioner/windows-shell/provisioner.go#L87-L123","documentation":"Windows-shell provisioner equivalent of error 5: Prepare() rejects a config that sets both the singular `script` and the plural `scripts` field. On Windows targets the same mutual-exclusion rule applies, and validation aborts before any machine is created.","triggerScenarios":"Prepare() on provisioner/windows-shell receives a config where p.config.Script != \"\" and len(p.config.Scripts) > 0, e.g. a windows-shell provisioner block containing both `script` and `scripts` keys.","commonSituations":"Converting a windows-shell block from a single .bat/.ps1 script to a list and forgetting to delete `script`; copying a linux shell block pattern that accidentally kept both keys; programmatically built configs merging two template sections.","solutions":["Delete one of the two keys so only `script` or only `scripts` remains.","To run several scripts, keep `scripts` (ordered list) and remove `script`.","To run one script, keep `script` and remove `scripts`."],"exampleFix":"// before\nprovisioner \"windows-shell\" {\n  script  = \"./setup.ps1\"\n  scripts = [\"./a.ps1\", \"./b.ps1\"]\n}\n// after\nprovisioner \"windows-shell\" {\n  scripts = [\"./a.ps1\", \"./b.ps1\"]\n}","handlingStrategy":"validation","validationCode":"if cfg.Script != \"\" && len(cfg.Scripts) > 0 {\n    return fmt.Errorf(\"windows-shell config: set only one of script or scripts\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use `scripts` (list) as the single source of truth for windows-shell script files.","Run `packer validate template.pkr.hcl` before builds to catch mutual exclusions.","Search templates for `script =` and `scripts =` co-occurring in the same block during refactors.","Write a Prepare() unit test for each windows-shell provisioner config you ship."],"tags":["packer","provisioner","config-validation","windows"],"backgroundTag":"mutually-exclusive-config-options","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"}