hashicorp/packer · error

write attestation %q: %w

Error message

write attestation %q: %w

What it means

After marshaling the unsigned attestation, writeAttestation writes it to `outputPath` via atomicWriteFile. Any filesystem error (permissions, missing directory, disk full, path is a directory) is wrapped as `write attestation %q: %w` with the path quoted.

Source

Thrown at post-processor/provenance/post-processor.go:289

	statement := internalprovenance.WrapInToto(subjects, predicateType, predicate)
	if err := p.writeAttestation(ctx, ui, statement, paths.SBOMAttestation); err != nil {
		return err
	}

	ui.Say(fmt.Sprintf("Wrote SBOM to %s", paths.SBOMRaw))
	return nil
}

func (p *PostProcessor) writeAttestation(ctx context.Context, ui packersdk.Ui, statement interface{}, outputPath string) error {
	if p.config.SigningMode == internalattestation.SigningModeNone {
		payload, err := json.MarshalIndent(statement, "", "  ")
		if err != nil {
			return fmt.Errorf("marshal attestation payload: %w", err)
		}

		if err := atomicWriteFile(outputPath, payload, 0664); err != nil {
			return fmt.Errorf("write attestation %q: %w", outputPath, err)
		}

		ui.Say(fmt.Sprintf("Wrote attestation to %s", outputPath))
		return nil
	}

	backendConfig, err := p.signingBackendConfig()
	if err != nil {
		return err
	}

	signer, verifier, err := p.signingResources(ctx, backendConfig)
	if err != nil {
		return err
	}

	payload, err := internalattestation.MarshalPayload(statement)
	if err != nil {

View on GitHub (pinned to eb36e3c3e4)

Solutions

  1. Create the parent directory: `mkdir -p $(dirname <output_path>)`.
  2. Check write permissions on the target directory (`ls -ld`, run as the right user).
  3. Ensure outputPath is a file path, not an existing directory.
  4. Check disk space and mount status if the error mentions 'no space left' or 'read-only'.

Example fix

// before
post-processor "provenance" { output_path = "/att/manifest.json" } // /att missing
// after
post-processor "provenance" { output_path = "./attestations/manifest.json" } // dir pre-created
Defensive patterns

Strategy: validation

Validate before calling

// check the output path is writable before the build
path := cfg.OutputPath
if dir := filepath.Dir(path); dir != "." {
    if err := os.MkdirAll(dir, 0o755); err != nil { return err }
}
if info, err := os.Stat(path); err == nil && info.IsDir() {
    return fmt.Errorf("output_path %q is a directory", path)
}
if f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, 0o664); err != nil {
    return err
} else { f.Close() }

Try / catch

if err := pp.PostProcess(ctx, ui, artifact); err != nil {
    if strings.Contains(err.Error(), "write attestation") {
        // check permissions/existence of the quoted path, then retry once after mkdir
    }
}

Prevention

When it happens

Trigger: PostProcess/writeSBOMAttestation with an output_path whose parent directory doesn't exist, is read-only, or is owned by another user; or outputPath itself is an existing directory.

Common situations: Running packer in a container where the output dir was never created; SELinux/read-only mounts; specifying a path inside a non-existent `output_dir`.

Understand the failure class

Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.

Related errors


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