hashicorp/packer · error

Can only have 1 input file when not using tar/zip. Found %d

Error message

Can only have 1 input file when not using tar/zip. Found %d files: %v

What it means

Packer's compress post-processor requires tar or zip packaging when the build artifact contains more than one file, because the bare-compression path can only io.Copy a single file into the compressor. The artifact had N != 1 files, so PostProcess aborts with the file count and list.

Source

Thrown at post-processor/compress/post-processor.go:227

	// Build an archive, if we're supposed to do that.
	switch p.config.Archive {
	case "tar":
		ui.Say(fmt.Sprintf("Tarring %s with %s", target, compression))
		err = createTarArchive(artifact.Files(), output)
		if err != nil {
			return nil, false, false, fmt.Errorf("Error creating tar: %s", err)
		}
	case "zip":
		ui.Say(fmt.Sprintf("Zipping %s", target))
		err = createZipArchive(artifact.Files(), output)
		if err != nil {
			return nil, false, false, fmt.Errorf("Error creating zip: %s", err)
		}
	default:
		// Filename indicates no tarball (just compress) so we'll do an io.Copy
		// into our compressor.
		if len(artifact.Files()) != 1 {
			return nil, false, false, fmt.Errorf(
				"Can only have 1 input file when not using tar/zip. Found %d "+
					"files: %v", len(artifact.Files()), artifact.Files())
		}
		archiveFile := artifact.Files()[0]
		ui.Say(fmt.Sprintf("Archiving %s with %s", archiveFile, compression))

		source, err := os.Open(archiveFile)
		if err != nil {
			return nil, false, false, fmt.Errorf(
				"Failed to open source file %s for reading: %s",
				archiveFile, err)
		}
		defer source.Close()

		if _, err = io.Copy(output, source); err != nil {
			return nil, false, false, fmt.Errorf("Failed to compress %s: %s",
				archiveFile, err)
		}

View on GitHub (pinned to eb36e3c3e4)

Solutions

  1. Add .tar to the output filename (e.g. "output.tar.gz") so multiple files are packaged
  2. Or set archive to "tar" (or "zip") explicitly in the post-processor config
  3. Or ensure the builder/artifact produces exactly one file
  4. Print/inspect artifact files to confirm which files are being compressed

Example fix

// before
output = "out/{{ .BuildName }}.xz"
// after
output = "out/{{ .BuildName }}.tar.xz"
Defensive patterns

Strategy: validation

Validate before calling

// enforce single-file compression contract before running the post-processor
if !strings.HasSuffix(cfg.OutputPath, ".tar") && !strings.HasSuffix(cfg.OutputPath, ".zip") {
    // bare-compress mode: the artifact must yield exactly one file
    // otherwise configure tar packaging
    if len(artifact.Files()) != 1 {
        return fmt.Errorf("artifact has %d files; use .tar in output_path", len(artifact.Files()))
    }
}

Try / catch

// Go: detect the config mistake and correct the filename
if err != nil && strings.Contains(err.Error(), "Can only have 1 input file") {
    cfg.OutputPath = strings.TrimSuffix(cfg.OutputPath, ".xz") + ".tar.xz"
    return pp.PostProcess(ctx, ui, artifact)
}

Prevention

When it happens

Trigger: Configured filename/output_path has no .tar/.zip extension (e.g. output "image.gz") while the upstream builder's artifact contains 0 or 2+ files — the default branch of the archive switch is entered with len(artifact.Files()) != 1.

Common situations: Using compression_algorithm like gzip/xz with a bare filename but a builder that emits multiple artifacts (e.g. multiple disks, ISO + checksum); forgetting the .tar in the output filename; post-processors earlier in the chain splitting the artifact.

Related errors


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