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 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
- Choose SPDX or CycloneDX for the whole pipeline.
- Set the generator output flag to that format explicitly.
- Match the attestation predicate type to the format you emit.
# 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.
syft convert sbom.spdx.json -o cyclonedx-json=sbom.cdx.jsonHow 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.