hashicorp/packer · error

scanner exited with status %d

Error message

scanner exited with status %d

What it means

Returned by runScanner (provisioner/hcp-sbom/provisioner.go:752) when the remote `packer sbom-generate` command ran but exited with a non-zero status. The scanner's stdout/stderr are printed to the UI just above this error, so the guest-side failure reason is in the build log.

Source

Thrown at provisioner/hcp-sbom/provisioner.go:752

		Stderr:  &stderr,
	}

	if err := comm.Start(ctx, cmd); err != nil {
		return "", fmt.Errorf("failed to start scanner: %s", err)
	}

	cmd.Wait()

	// Log output
	if stdout.Len() > 0 {
		ui.Say(fmt.Sprintf("Scanner stdout: %s", stdout.String()))
	}
	if stderr.Len() > 0 {
		ui.Say(fmt.Sprintf("Scanner stderr: %s", stderr.String()))
	}

	if cmd.ExitStatus() != 0 {
		return "", fmt.Errorf("scanner exited with status %d", cmd.ExitStatus())
	}

	return outputPath, nil
}

func normalizeScannerExecuteCommand(executeCommand string) string {
	// Walk each {{.Path}} token and only inject "sbom-generate" when that
	// token is being used as the scanner executable invocation.
	//
	// Example rewritten:
	//   chmod +x {{.Path}} && {{.Path}} {{.Args}} {{.ScanPath}} > {{.Output}}
	// becomes:
	//   chmod +x {{.Path}} && {{.Path}} sbom-generate {{.Args}} {{.ScanPath}} > {{.Output}}
	//
	// Example left unchanged:
	//   chmod +x {{.Path}} && {{.Path}} version
	// because the token after {{.Path}} is not {{.Args}} or {{.ScanPath}}.
	var out strings.Builder

View on GitHub (pinned to eb36e3c3e4)

Solutions

  1. Read 'Scanner stdout/stderr' lines in the build output immediately above the error — they contain the guest-side reason.
  2. Verify scan_path exists on the guest and is readable by the user running execute_command; add sudo if it needs root.
  3. Ensure execute_command keeps `chmod +x {{.Path}}` before invoking {{.Path}}.
  4. Validate scanner_args against the underlying scanner's CLI (try the same args manually on a similar machine).
  5. Check exit code meaning: 126/127 usually means permission denied / command not found in the rendered command.

Example fix

// before: scanner not executable, exits 126
execute_command = "{{.Path}} sbom-generate {{.Args}} {{.ScanPath}} > {{.Output}}"
// after: chmod before execution
execute_command = "chmod +x {{.Path}} && sudo {{.Path}} sbom-generate {{.Args}} {{.ScanPath}} > {{.Output}}"
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-validate the guest can run the scanner
// execute_command must include: chmod +x {{.Path}} && ...
// scan_path must exist in the guest image (bake it in or verify in an earlier provisioner)

Try / catch

if cmd.ExitStatus() != 0 {
    // stdout/stderr were already surfaced via ui.Say; include them for context
    return "", fmt.Errorf("scanner exited with status %d: %s", cmd.ExitStatus(), stderr.String())
}

Prevention

When it happens

Trigger: The scanner command executes successfully at the transport level but returns a non-zero exit code: sbom-generate cannot read ScanPath, the scanner binary lacks execute permission (missing chmod), scan tool inside fails (no root, missing dependency), or scanner_args are invalid.

Common situations: ScanPath pointing to a directory that does not exist in the guest; running without sudo when the scanner needs root; customized execute_command that dropped the `chmod +x {{.Path}}` prefix; scanner_args typo causing CLI usage error; SELinux preventing execution from /tmp.

Related errors


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