{"record":{"id":"53db8a97aa6bcb28","repo":"hashicorp/packer","slug":"sbom-true-requires-sbom-scan-path-when-artifact-fi","errorCode":null,"errorMessage":"sbom=true requires sbom_scan_path when artifact files span multiple directories","messagePattern":"sbom=true requires sbom_scan_path when artifact files span multiple directories","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"post-processor/provenance/post-processor.go","lineNumber":489,"sourceCode":"\t}\n\n\treturn format, rawSBOM, nil\n}\n\nfunc (p *PostProcessor) resolveSBOMScanPath(source packersdk.Artifact) (string, error) {\n\tif p.config.SBOMScanPath != \"\" {\n\t\treturn p.config.SBOMScanPath, nil\n\t}\n\n\tfiles := source.Files()\n\tif len(files) == 1 {\n\t\treturn files[0], nil\n\t}\n\tif len(files) > 1 {\n\t\tparent := filepath.Dir(files[0])\n\t\tfor _, file := range files[1:] {\n\t\t\tif filepath.Dir(file) != parent {\n\t\t\t\treturn \"\", fmt.Errorf(\"sbom=true requires sbom_scan_path when artifact files span multiple directories\")\n\t\t\t}\n\t\t}\n\t\treturn parent, nil\n\t}\n\n\treturn \"\", fmt.Errorf(\"sbom=true requires local artifact files or sbom_scan_path\")\n}\n\nfunc buildSBOMPredicate(rawSBOM []byte, format internalsbom.Format) (interface{}, string, error) {\n\tdecoder := json.NewDecoder(bytes.NewReader(rawSBOM))\n\tdecoder.UseNumber()\n\n\tvar predicate interface{}\n\tif err := decoder.Decode(&predicate); err != nil {\n\t\treturn nil, \"\", fmt.Errorf(\"decode SBOM payload: %w\", err)\n\t}\n\n\tswitch format {","sourceCodeStart":471,"sourceCodeEnd":507,"githubUrl":"https://github.com/hashicorp/packer/blob/eb36e3c3e48a036f3e8cc94087636ee72e1303c9/post-processor/provenance/post-processor.go#L471-L507","documentation":"The provenance post-processor throws this when sbom=true but the artifact exposes more than one file and those files do not all live in the same directory. Packer would otherwise guess a scan root from the files, and a multi-directory spread makes that guess ambiguous, so it refuses and asks for an explicit sbom_scan_path.","triggerScenarios":"Configure the provenance post-processor with sbom=true, leave sbom_scan_path unset, and have the artifact's Files() list contain paths whose filepath.Dir values differ (e.g. 'out/a/pkg.tar' plus 'out/b/manifest.json').","commonSituations":"Artifacts from builders that emit multiple outputs (a file builder writing several files, or a manifest/artifact-export chain) combined with sbom=true and no explicit scan path; also happens after changing output config so files no longer share a directory.","solutions":["Set sbom_scan_path in the provenance post-processor config to the directory (or file) to scan","Restructure the build so all artifact files land in one directory","Set sbom=false if SBOM attestation is not needed"],"exampleFix":"// before\npost-processors {\n  post-processor provenance {\n    sbom = true\n  }\n}\n// after\npost-processors {\n  post-processor provenance {\n    sbom = true\n    sbom_scan_path = \"./output\"\n  }\n}","handlingStrategy":"validation","validationCode":"// In your template config, before running packer build\n// if sbom = true, make sure artifact files share a dir or set the path:\nfiles := artifact.Files()\nif len(files) > 1 {\n    parent := filepath.Dir(files[0])\n    for _, f := range files[1:] {\n        if filepath.Dir(f) != parent {\n            fmt.Println(\"set sbom_scan_path explicitly\")\n        }\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always set sbom_scan_path when sbom=true unless the artifact is a single local file","Keep artifact outputs in one flat output directory","Run packer validate / a dry build to exercise resolveSBOMScanPath early"],"tags":["packer","provenance","sbom","config"],"backgroundTag":"sbom-scan-path-required","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"}