hashicorp/packer · error

Bad source '%s': %s

Error message

Bad source '%s': %s

What it means

During Prepare of the file provisioner (direction=upload), each configured source is stat'ed on the host. When generated=false (the default, expressed here as == false) and os.Stat fails — usually the file does not exist — this error is appended to the validation errors. The %s carries the underlying OS error (e.g. 'no such file or directory').

Source

Thrown at provisioner/file/provisioner.go:111

	if p.config.Direction == "" {
		p.config.Direction = "upload"
	}

	var errs *packersdk.MultiError

	if p.config.Direction != "download" && p.config.Direction != "upload" {
		errs = packersdk.MultiErrorAppend(errs,
			errors.New("Direction must be one of: download, upload."))
	}
	if p.config.Source != "" {
		p.config.Sources = append(p.config.Sources, p.config.Source)
	}

	if p.config.Direction == "upload" {
		for _, src := range p.config.Sources {
			if _, err := os.Stat(src); p.config.Generated == false && err != nil {
				errs = packersdk.MultiErrorAppend(errs,
					fmt.Errorf("Bad source '%s': %s", src, err))
			}
		}
	}

	if len(p.config.Sources) > 0 && p.config.Content != "" {
		errs = packersdk.MultiErrorAppend(errs,
			errors.New("source(s) conflicts with content."))
	}

	if p.config.Destination == "" {
		errs = packersdk.MultiErrorAppend(errs,
			errors.New("Destination must be specified."))
	}

	if errs != nil && len(errs.Errors) > 0 {
		return errs
	}

View on GitHub (pinned to eb36e3c3e4)

Solutions

  1. Create the source file or fix the path before running packer
  2. Set generated = true if the file is produced at runtime by generated data / a prior provisioner so the stat check is skipped
  3. Use an absolute path or correct the relative path relative to the template's directory
  4. Switch direction to download if you actually meant to fetch a file from the machine

Example fix

// before
provisioner file {
  source      = "app.tar.gz"
  destination = "/tmp/app.tar.gz"
}
// after
provisioner file {
  source      = "app.tar.gz"
  destination = "/tmp/app.tar.gz"
  generated   = true
}
Defensive patterns

Strategy: validation

Validate before calling

// Pre-validate upload sources in shell before packer build:
for f in $SOURCES; do test -e "$f" || echo "missing: $f"; done
// In Go config validation:
for _, src := range cfg.Sources {
    if _, err := os.Stat(src); err != nil && !cfg.Generated {
        fmt.Printf("source will fail validation: %s (%v)\n", src, err)
    }
}

Prevention

When it happens

Trigger: file provisioner with direction "upload" (the default), a source path that does not exist on the build host at template-validation time, and generated not set to true.

Common situations: Typo in the source path; the file is produced later by a previous provisioner or build step but `generated` was not set; relative path resolved from a different working directory; path valid on the remote but being used for upload.

Related errors


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