{"record":{"id":"f0a5f4dddce3de81","repo":"hashicorp/packer","slug":"can-only-have-1-input-file-when-not-using-tar-zip","errorCode":null,"errorMessage":"Can only have 1 input file when not using tar/zip. Found %d files: %v","messagePattern":"Can only have 1 input file when not using tar/zip\\. Found (.+?) files: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"post-processor/compress/post-processor.go","lineNumber":227,"sourceCode":"\t// Build an archive, if we're supposed to do that.\n\tswitch p.config.Archive {\n\tcase \"tar\":\n\t\tui.Say(fmt.Sprintf(\"Tarring %s with %s\", target, compression))\n\t\terr = createTarArchive(artifact.Files(), output)\n\t\tif err != nil {\n\t\t\treturn nil, false, false, fmt.Errorf(\"Error creating tar: %s\", err)\n\t\t}\n\tcase \"zip\":\n\t\tui.Say(fmt.Sprintf(\"Zipping %s\", target))\n\t\terr = createZipArchive(artifact.Files(), output)\n\t\tif err != nil {\n\t\t\treturn nil, false, false, fmt.Errorf(\"Error creating zip: %s\", err)\n\t\t}\n\tdefault:\n\t\t// Filename indicates no tarball (just compress) so we'll do an io.Copy\n\t\t// into our compressor.\n\t\tif len(artifact.Files()) != 1 {\n\t\t\treturn nil, false, false, fmt.Errorf(\n\t\t\t\t\"Can only have 1 input file when not using tar/zip. Found %d \"+\n\t\t\t\t\t\"files: %v\", len(artifact.Files()), artifact.Files())\n\t\t}\n\t\tarchiveFile := artifact.Files()[0]\n\t\tui.Say(fmt.Sprintf(\"Archiving %s with %s\", archiveFile, compression))\n\n\t\tsource, err := os.Open(archiveFile)\n\t\tif err != nil {\n\t\t\treturn nil, false, false, fmt.Errorf(\n\t\t\t\t\"Failed to open source file %s for reading: %s\",\n\t\t\t\tarchiveFile, err)\n\t\t}\n\t\tdefer source.Close()\n\n\t\tif _, err = io.Copy(output, source); err != nil {\n\t\t\treturn nil, false, false, fmt.Errorf(\"Failed to compress %s: %s\",\n\t\t\t\tarchiveFile, err)\n\t\t}","sourceCodeStart":209,"sourceCodeEnd":245,"githubUrl":"https://github.com/hashicorp/packer/blob/eb36e3c3e48a036f3e8cc94087636ee72e1303c9/post-processor/compress/post-processor.go#L209-L245","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Add .tar to the output filename (e.g. \"output.tar.gz\") so multiple files are packaged","Or set archive to \"tar\" (or \"zip\") explicitly in the post-processor config","Or ensure the builder/artifact produces exactly one file","Print/inspect artifact files to confirm which files are being compressed"],"exampleFix":"// before\noutput = \"out/{{ .BuildName }}.xz\"\n// after\noutput = \"out/{{ .BuildName }}.tar.xz\"","handlingStrategy":"validation","validationCode":"// enforce single-file compression contract before running the post-processor\nif !strings.HasSuffix(cfg.OutputPath, \".tar\") && !strings.HasSuffix(cfg.OutputPath, \".zip\") {\n    // bare-compress mode: the artifact must yield exactly one file\n    // otherwise configure tar packaging\n    if len(artifact.Files()) != 1 {\n        return fmt.Errorf(\"artifact has %d files; use .tar in output_path\", len(artifact.Files()))\n    }\n}","typeGuard":null,"tryCatchPattern":"// Go: detect the config mistake and correct the filename\nif err != nil && strings.Contains(err.Error(), \"Can only have 1 input file\") {\n    cfg.OutputPath = strings.TrimSuffix(cfg.OutputPath, \".xz\") + \".tar.xz\"\n    return pp.PostProcess(ctx, ui, artifact)\n}","preventionTips":["Match the output filename extension to the intended packaging (.tar.gz vs .gz)","Use packer validate / inspect to confirm the artifact file count","Explicitly set archive = \"tar\" when unsure about file count","Check whether earlier post-processors change artifact composition"],"tags":["packer","post-processor","config","archive"],"backgroundTag":"archive-requires-tar-or-zip","analyzedSha":"eb36e3c3e48a036f3e8cc94087636ee72e1303c9","analyzedAt":"2026-09-05T13:20:43.127Z","contentChangedAt":"2026-09-05T13:20:43.127Z","schemaVersion":2},"datasetVersion":"2026-09-12T17:17:11.597Z"}