Skip to content
Latchkey

SBOM SPDX vs CycloneDX format mismatch between tools in CI

SPDX and CycloneDX are different SBOM specifications. A generator that writes one format hands a file the next tool cannot read when that tool expects the other, breaking the scan or attestation step.

What this error means

A consumer (grype, trivy, cosign attest, a policy) rejects the SBOM with a decode or format error, while the file itself is a perfectly valid SBOM in the other specification.

sbom
# SBOM was emitted as SPDX, but the predicate type says CycloneDX
Error: unable to decode SBOM: bomFormat field not found (expected CycloneDX)

Common causes

Generator and consumer disagree on the spec

syft defaults can differ from what a downstream tool expects; SPDX JSON has spdxVersion, CycloneDX JSON has bomFormat, and neither parser reads the other.

The attestation predicate type does not match the file

Attesting an SPDX file under a CycloneDX predicate type (or the reverse) makes verifiers reject the payload as the wrong SBOM kind.

How to fix it

Pick one format and emit it everywhere

  1. Choose SPDX or CycloneDX for the whole pipeline.
  2. Set the generator output flag to that format explicitly.
  3. Match the attestation predicate type to the format you emit.
Terminal
# CycloneDX end to end
syft dir:. -o cyclonedx-json=sbom.cdx.json
cosign attest --predicate sbom.cdx.json --type cyclonedx <image>

Convert between formats when a tool demands the other

When a consumer only reads one spec, convert the SBOM rather than regenerating from scratch, keeping the same component set.

Terminal
syft convert sbom.spdx.json -o cyclonedx-json=sbom.cdx.json

How to prevent it

  • Standardize on one SBOM specification across generation, scanning, and attestation.
  • Set the predicate type to match the SBOM format when attesting.
  • Document the chosen format so new steps emit and consume the same spec.

Related guides

Tired of flaky CI? Latchkey auto-heals failed jobs and retries them for you. Start free →