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

The PowerShell provisioner accepts a single script via the script field or a list via scripts, but never both. Prepare detects p.config.Script non-empty and len(p.config.Scripts) > 0 simultaneously and rejects the template because it cannot unambiguously determine which set of scripts to execute. This is ambiguous-configuration validation raised before any provisioning starts.

Source

Thrown at provisioner/powershell/provisioner.go:226

	if p.config.RemoteEnvVarPath == "" {
		uuid := uuid.TimeOrderedUUID()
		p.config.RemoteEnvVarPath = fmt.Sprintf(`c:/Windows/Temp/packer-ps-env-vars-%s.ps1`, uuid)
	}

	if p.config.Scripts == nil {
		p.config.Scripts = make([]string, 0)
	}

	if p.config.Vars == nil {
		p.config.Vars = make([]string, 0)
	}

	p.config.remoteCleanUpScriptPath = fmt.Sprintf(`c:/Windows/Temp/packer-cleanup-%s.ps1`, uuid.TimeOrderedUUID())

	var errs error
	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.ElevatedUser == "" && p.config.ElevatedPassword != "" {
		errs = packersdk.MultiErrorAppend(errs,
			errors.New("Must supply an 'elevated_user' if 'elevated_password' provided"))
	}

	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."))
	}

View on GitHub (pinned to eb36e3c3e4)

Solutions

  1. Remove the script field and keep only scripts (move the single entry into the list).
  2. Or remove scripts and keep only script if a single file is needed.
  3. Check generated/HCL for-each logic that may set both fields from variables.

Example fix

// before
provisioner "powershell" {
  script  = "./setup.ps1"
  scripts = ["./install.ps1", "./config.ps1"]
}

// after
provisioner "powershell" {
  scripts = ["./setup.ps1", "./install.ps1", "./config.ps1"]
}
Defensive patterns

Strategy: validation

Validate before calling

// Before defining the block, pick one field:
// single file  -> script = "./x.ps1"
// multiple     -> scripts = ["./a.ps1"]
// Never set both. Template assertion:
assert {
  condition     = !(var.use_single && var.use_multi)
  error_message = "Configure either script or scripts, not both."
}

Prevention

When it happens

Trigger: A powershell provisioner block defining both script = "./a.ps1" and scripts = ["./b.ps1", "./c.ps1"]. Often happens after HCL2 variable interpolation injects a value into both fields.

Common situations: Merging snippet configs or modules where each sets a different field; converting a single-script block to scripts and forgetting to remove the old script key; conditional template logic accidentally populating both.

Related errors


AI-assisted analysis of hashicorp/packer@eb36e3c3e4 (2026-09-05). Data as JSON: /api/errors/16b70cbc1071adf6. Report an issue: GitHub.