hashicorp/packer · error
Only one of script or scripts can be specified.
Error message
Only one of script or scripts can be specified.
What it means
This is a template-validation error thrown by the shell provisioner's Prepare() phase in Packer. The provisioner accepts two mutually exclusive ways to supply a script: the singular `script` field and the plural `scripts` list. If both are set in the same provisioner block, Prepare refuses to guess which one to use and returns this error before any build runs.
Source
Thrown at provisioner/shell/provisioner.go:152
p.config.RemoteFile = fmt.Sprintf("script_%d.sh", rand.Intn(9999))
}
if p.config.RemotePath == "" {
p.config.RemotePath = fmt.Sprintf("%s/%s", p.config.RemoteFolder, p.config.RemoteFile)
}
if p.config.Scripts == nil {
p.config.Scripts = make([]string, 0)
}
if p.config.Vars == nil {
p.config.Vars = make([]string, 0)
}
var errs *packersdk.MultiError
if p.config.Script != "" && len(p.config.Scripts) > 0 {
errs = packersdk.MultiErrorAppend(errs,
errors.New("Only one of script or scripts can be specified."))
}
if p.config.Script != "" {
p.config.Scripts = []string{p.config.Script}
}
if len(p.config.Scripts) == 0 && p.config.Inline == nil {
errs = packersdk.MultiErrorAppend(errs,
errors.New("Either a script file or inline script must be specified."))
} else if len(p.config.Scripts) > 0 && p.config.Inline != nil {
errs = packersdk.MultiErrorAppend(errs,
errors.New("Only a script file or an inline script can be specified, not both."))
}
for _, path := range p.config.Scripts {
if _, err := os.Stat(path); err != nil {
errs = packersdk.MultiErrorAppend(errs,
fmt.Errorf("Bad script '%s': %s", path, err))View on GitHub (pinned to eb36e3c3e4)
Solutions
- Remove either the `script` or the `scripts` key from the provisioner block so only one remains.
- If you want multiple scripts, delete `script` and list every file in `scripts`.
- If you only need one script, keep `script` and delete the `scripts` list.
Example fix
// before
provisioner "shell" {
script = "./setup.sh"
scripts = ["./a.sh", "./b.sh"]
}
// after
provisioner "shell" {
scripts = ["./a.sh", "./b.sh"]
} Defensive patterns
Strategy: validation
Validate before calling
if cfg.Script != "" && len(cfg.Scripts) > 0 {
return fmt.Errorf("provisioner config: set only one of script or scripts")
} Prevention
- Pick one canonical field per provisioner block; prefer `scripts` when in doubt.
- Lint templates for coexisting `script` and `scripts` keys before `packer build`.
- Validate early: call Provisioner.Prepare() in tests with your config instead of discovering it at build time.
- When migrating single-script templates, delete the old `script` key in the same change.
When it happens
Trigger: Calling Prepare() with a config where p.config.Script is a non-empty string AND p.config.Scripts has length > 0 (e.g. HCL2/JSON template sets both `script = "a.sh"` and `scripts = ["b.sh"]` in the same shell provisioner block).
Common situations: Users migrating an old single-script template to a multi-script layout and leaving the old `script` key behind; copy-pasting a provisioner block that already had `scripts` and adding `script` for a quick test; SDK/plugin code programmatically populating both fields from overlapping template sections.
Related errors
- Either a script file or inline script must be specified.
- Only a script file or an inline script can be specified, not
- source must be specified when auto_generate is not enabled
- Only one of script or scripts can be specified.
- Must supply an 'elevated_user' if 'elevated_password' provid
AI-assisted analysis of hashicorp/packer@eb36e3c3e4 (2026-09-05).
Data as JSON: /api/errors/3c2801e56bf9c442.
Report an issue: GitHub.