hashicorp/packer · error

Error interpolating destination

Error message

Error interpolating destination: %s

What it means

In ProvisionDownload, the destination path is run through Packer's interpolate renderer (to substitute build-generated data like {{ .WinRMUser }} etc.). If the template contains an unknown key, bad syntax, or references data not available, rendering fails and this error aborts the download before any file transfer.

Solutions

  1. Fix the template syntax in destination (valid HCL2/Packer template functions or generated data keys)
  2. Only use generated-data variables supported by the builder in use
  3. Remove interpolation braces if a literal path with '{{' was intended
  4. Check packer validate output for the specific interpolation error

Example fix

// before
destination = "/tmp/{{ .UnsupportedVar }}/out.txt"
// after
destination = "/tmp/{{ build_name }}-out.txt"
Defensive patterns

Strategy: try-catch

Validate before calling

// Verify the destination template renders with expected generated data before build:
// packer validate template.pkr.hcl  (interpolation errors surface at validate)
// and confirm the builder exposes the generated-data keys you use.

Try / catch

if err := provision(ctx, ui, comm, generated); err != nil {
    if strings.Contains(err.Error(), "Error interpolating destination") {
        // fix the destination template / generated-data key
    }
}

Prevention

When it happens

Trigger: direction=download and config.Destination contains template syntax ({{ }}) that fails to render — unknown variables, malformed placeholders, or generated data keys not exposed by the builder.

Common situations: Using {{ .WinRMUser }} on an SSH builder; typos like {{ build_name }} without the right function; escaped braces from shell copying; copy-pasting a destination from another builder type.

Related errors


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

Appendix: source

Thrown at provisioner/file/provisioner.go:162

		defer file.Close()
		if _, err := file.WriteString(p.config.Content); err != nil {
			return err
		}
		p.config.Content = ""
		p.config.Sources = append(p.config.Sources, file.Name())
	}

	if p.config.Direction == "download" {
		return p.ProvisionDownload(ui, comm)
	} else {
		return p.ProvisionUpload(ui, comm)
	}
}

func (p *Provisioner) ProvisionDownload(ui packersdk.Ui, comm packersdk.Communicator) error {
	dst, err := interpolate.Render(p.config.Destination, &p.config.ctx)
	if err != nil {
		return fmt.Errorf("Error interpolating destination: %s", err)
	}
	for _, src := range p.config.Sources {
		dst := dst
		src, err := interpolate.Render(src, &p.config.ctx)
		if err != nil {
			return fmt.Errorf("Error interpolating source: %s", err)
		}

		// ensure destination dir exists.  p.config.Destination may either be a file or a dir.
		dir := dst
		// if it doesn't end with a /, set dir as the parent dir
		if !strings.HasSuffix(dst, "/") {
			dir = filepath.Dir(dir)
		} else if !strings.HasSuffix(src, "/") && !strings.HasSuffix(src, "*") {
			dst = filepath.Join(dst, filepath.Base(src))
		}
		ui.Say(fmt.Sprintf("Downloading %s => %s", src, dst))

View on GitHub (pinned to eb36e3c3e4)