SPDX Documents, Validated: Licences, Packages and the Checks That Catch Errors
Modern software is assembled from dozens or hundreds of components, each with its own licence, and nobody can read every licence file by hand for every release. SPDX, short for Software Package Data Exchange, is a standard format for recording that information in a structured document: which packages are included, what version each one is, who supplied it, and under which licence it is distributed. A bill of materials built this way lets a team answer questions that used to take days of digging, such as which licences are in this release, whether any of them conflict, and what changed since the last release. The SPDX Validator checks a document you paste in, testing whether its structure and its licence identifiers follow the standard, so errors are caught before the document is shared with a customer, an auditor, or a compliance team.
An SPDX document has two common shapes, a tag-value text format and a JSON format, and both describe the same facts. At the top sits the document itself, with a name, a unique identifier, and the licence under which the document is shared. Below that come the packages, each with a name, a version, a supplier, a download location, and a concluded licence, which is the licence the document author has determined applies, plus a declared licence, which is what the package itself claims. Files can also be listed, with checksums that identify their exact contents. The validator's job is to check that required fields are present, that identifiers are unique and correctly formed, that licence expressions use recognised identifiers and operators, and that references point at things that actually exist in the document.
How it works
Validation happens in layers, and understanding the layers explains why a document can parse correctly yet still fail validation. The first layer is syntax: is the JSON well-formed, or is the tag-value text laid out the way the standard requires? A missing bracket or a misspelled field name fails here. The second layer is structure: does every package carry the fields the standard marks as required, and do identifiers follow the required pattern, such as starting with SPDXRef-? A package without a name or a document without an identifier fails here. The third layer is vocabulary: are the licence identifiers real? SPDX maintains a published list of licence identifiers, such as MIT, Apache-2.0, and GPL-3.0-only, and a validator compares each identifier in the document against that list. A plausible-looking but invented identifier, or a common misspelling such as Apache 2.0 with a space instead of a hyphen, fails here, and this layer catches a surprising number of real errors, because people type licence names from memory.
The fourth layer is consistency: do the references resolve? If a package claims a relationship to another package, that other package must exist in the document. If a file lists a checksum, the checksum algorithm must be one the standard recognises, and the value must be the right length for that algorithm. If a licence expression combines identifiers with AND, OR, and WITH operators, the expression must be balanced and the operators must be used in a way the standard allows. None of these checks proves that the licence conclusion is legally correct, which is a human judgement, but they do prove that the document says what its author thinks it says in a form other tools can read, and that is the foundation everything else rests on.
Worked example
Consider a small sample document describing a fictional application with three packages, using sample values for illustration. The first package is a web framework, version 4.2.0, concluded licence MIT. The second is a charting library, version 3.1.5, concluded licence Apache-2.0. The third is a data parser, version 1.0.9, concluded licence BSD-3-Clause. The validator runs its checks and reports two findings. First, the charting library's licence is written as Apache 2.0, with a space, which is not a recognised identifier, so the validator flags it and suggests Apache-2.0. Second, the data parser lists a relationship to a package identifier that does not exist anywhere else in the document, because a package was renamed during editing and the relationship was not updated.
Fixing both is straightforward: correct the identifier to Apache-2.0, and either restore the missing package or correct the relationship to point at the renamed package. After the fix, the document validates cleanly, and a downstream tool can now answer the question the document exists to answer: this release contains 3 packages under 3 licences, MIT, Apache-2.0, and BSD-3-Clause, with no copyleft licence present. Before the fix, the same question would have produced an uncertain answer, because one licence was unreadable and one relationship was broken. That is the practical value of validation: it converts a document that looks complete into one that other tools can actually rely on.
Mistakes to avoid
The most frequent mistake is writing licence names as people say them rather than as the standard spells them. Apache 2.0, GPL v3, and BSD are all understandable to a human and all wrong as identifiers; the correct forms are Apache-2.0, GPL-3.0-only or GPL-3.0-or-later, and BSD-2-Clause or BSD-3-Clause, and the difference matters because tools match identifiers exactly. A second mistake is confusing the concluded licence with the declared licence. The declared licence is what the package claims, the concluded licence is what the author determined after review, and when they differ, the difference itself is information that should be recorded, not hidden by copying one into the other. A third mistake is leaving the document identifier, the package identifiers, or the checksums to chance. Identifiers must be unique within the document, and checksums must match the files they describe, or the document cannot be used to verify that a delivered package is the package described.
A fourth mistake is treating a passing validation as legal advice. A validator checks form, not legal truth: it can confirm that MIT is spelled correctly, but it cannot confirm that the package really is under the MIT licence, nor whether two licences in the same product are compatible. Licence compatibility and legal interpretation need human review, ideally from someone qualified. Finally, never paste secrets into a validator. An SPDX document describes public licence facts, but build documents sometimes sit alongside credentials, tokens, or private repository addresses, and none of those belong in a pasted document. Strip anything private before validating, and treat a document that contains a secret as compromised until the secret is rotated.
Putting it into practice
Generate SPDX documents from your build tooling rather than writing them by hand, because hand-written documents drift from reality with every release. Validate the generated document on every release, fix findings before sharing it, and keep the validated document alongside the release it describes, so the bill of materials for version 2.3 is still available when version 2.3 is the one under audit a year later. Neighbouring checks include the SBOM Viewer for reading a bill of materials in structured form, and the Hash Generator for producing checksums in the formats a document can carry. For background reading, the related guide explains checksums and digests, which are the mechanism that ties an SPDX file entry to the exact file it describes.
Key points
- An SPDX document records packages, versions, suppliers, and licences in a standard form
- Validation checks syntax, structure, licence identifiers, and whether references resolve
- Licence identifiers must match the published list exactly, including hyphens
- A passing validation proves the document is well-formed, not that its legal conclusions are correct