hashicorp/packer · error
Environment variable not in format 'key=value': %s
Error message
Environment variable not in format 'key=value': %s
What it means
Raised in the windows-shell provisioner's Prepare when an entry in the provisioner's `environment_vars` (Vars) is not a well-formed `key=value` string. Each var is split on the first '=' with strings.SplitN(kv, "=", 2); the error fires when there is no '=' at all or the key side is empty. This prevents generating broken `set VAR=...` shell lines on the guest.
Source
Thrown at provisioner/windows-shell/provisioner.go:132
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))
}
}
// Do a check for bad environment variables, such as '=foo', 'foobar'
for _, kv := range p.config.Vars {
vs := strings.SplitN(kv, "=", 2)
if len(vs) != 2 || vs[0] == "" {
errs = packersdk.MultiErrorAppend(errs,
fmt.Errorf("Environment variable not in format 'key=value': %s", kv))
}
}
return errs
}
// This function takes the inline scripts, concatenates them
// into a temporary file and returns a string containing the location
// of said file.
func extractScript(p *Provisioner) (string, error) {
temp, err := tmp.File("windows-shell-provisioner")
if err != nil {
log.Printf("Unable to create temporary file for inline scripts: %s", err)
return "", err
}
writer := bufio.NewWriter(temp)
for _, command := range p.config.Inline {
log.Printf("Found command: %s", command)View on GitHub (pinned to eb36e3c3e4)
Solutions
- Rewrite each environment_vars entry as `KEY=value`, e.g. environment_vars = ["MYVAR=foo"] instead of ["MYVAR"].
- Check interpolated template variables: ensure the key part resolves to a non-empty name (avoid "${var.name}=x" when var.name is empty).
- Remove empty strings from the environment_vars array in your HCL/JSON template.
- If the value legitimately needs '=', that is fine — only the key side before the first '=' must be non-empty.
Example fix
// before
provisioner "windows-shell" {
environment_vars = ["HTTP_PROXY", "API_KEY=${var.key}"]
}
// after: every entry is key=value
provisioner "windows-shell" {
environment_vars = ["HTTP_PROXY=http://proxy:8080", "API_KEY=${var.key}"]
} Defensive patterns
Strategy: validation
Validate before calling
func validEnvVars(vars []string) error {
for _, kv := range vars {
parts := strings.SplitN(kv, "=", 2)
if len(parts) != 2 || parts[0] == "" {
return fmt.Errorf("env var not key=value: %q", kv)
}
}
return nil
} Try / catch
// catch at template lint time
if err := validEnvVars(cfg.EnvironmentVars); err != nil {
return fmt.Errorf("windows-shell environment_vars invalid: %w", err)
} Prevention
- Always write environment_vars entries as KEY=value, never bare names.
- Lint templates for empty interpolations like "=${env.X}" that can produce empty keys.
- Run `packer validate` before builds; it exercises Prepare.
- Keep var lists generated from structured data rather than hand-edited strings.
When it happens
Trigger: Prepare validation loops over p.config.Vars and appends this error for any string where SplitN yields fewer than 2 parts or vs[0] == "" — e.g. "FOO" (no '='), "=bar" (empty key), or "=value with spaces". windows-shell/provisioner.go:131-137.
Common situations: User writes environment_vars = ["MYVAR"] forgetting the value; template variable interpolation producing an empty key like "=${env.MISSING}"; copying a list of var names instead of key=value pairs; whitespace/newline typos in JSON/HCL arrays.
Understand the failure class
Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.
Related errors
- Bad script '%s': %s
- Only one of script or scripts can be specified.
- Either a script file or inline script must be specified.
- `max_retries` must be a valid integer: %s
- failed to open Packer release zip: %s
AI-assisted analysis of hashicorp/packer@eb36e3c3e4 (2026-09-05).
Data as JSON: /api/errors/54c27dccf082f899.
Report an issue: GitHub.