← Back to Blog

Fixing "Supplier is a minimum element and must not be empty" in CycloneDX SBOMs

· Verimu
CycloneDXNTIASBOMCRA ComplianceSupplier

If you've ever run a CycloneDX SBOM through the FOSSA NTIA SBOM Validator or a similar tool, you may have seen errors like these:

Supplier is a minimum element and must not be empty. Path: metadata.supplier Rule: Metadata.supplier

Supplier is a minimum element and must not be empty. Path: components.pkg:npm/express@4.18.2.supplier Rule: Component.supplier

These failures mean your SBOM is technically valid CycloneDX — it passes schema validation — but it doesn't meet the NTIA minimum elements for a Software Bill of Materials. If you're selling software in the EU under the Cyber Resilience Act (CRA), or delivering to a U.S. federal agency, NTIA compliance typically isn't optional.

Let's break down what's happening and how to fix it.

What the NTIA minimum elements require

The NTIA published its "Minimum Elements for a Software Bill of Materials" in 2021. Among the required data fields for every SBOM are:

Field Description
Supplier Name The name of the entity that creates, defines, and identifies components
Component Name The name assigned to a unit of software
Version The version of the component
Unique Identifier A unique identifier (such as PURL or CPE)
Dependency Relationship Which components are dependencies of which
Author of SBOM Data Who created the SBOM itself
Timestamp When the SBOM was generated

The Supplier Name is required in three distinct places in a CycloneDX SBOM:

  1. metadata.supplier — the organization supplying the software being described
  2. metadata.component.supplier — the supplier of the top-level component
  3. components[].supplier — the supplier of every listed dependency

Most SBOM generators, including popular tools like Syft and Trivy, historically omitted these fields. CycloneDX schema validation doesn't require them — they're optional in the spec. But NTIA validation does, and that's what matters for compliance.

The root cause

When you run npm install or pip install, the resulting lockfile (package-lock.json, requirements.txt, etc.) records package names, versions, and dependency relationships. What it doesn't record is who published each package. That metadata lives in the package registry (npmjs.org, PyPI, etc.), not in your lockfile.

Most SBOM generators parse the lockfile and nothing else. Result: every component gets a name and version, but no supplier. The SBOM is schema-valid but NTIA-noncompliant.

The fix: populate supplier fields at every level

1. Metadata supplier

Your SBOM's metadata section needs a supplier object with at least a name:

{
  "metadata": {
    "supplier": {
      "name": "your-project-name"
    },
    "component": {
      "type": "application",
      "name": "your-project-name",
      "version": "1.0.0",
      "supplier": {
        "name": "your-project-name"
      }
    }
  }
}

The metadata.supplier represents the organization supplying the software described by this SBOM. For most teams, this is your project or company name.

2. Tool supplier

If your SBOM lists the generating tool under metadata.tools, each tool should also carry a supplier:

{
  "tools": [
    {
      "name": "your-sbom-tool",
      "version": "1.0.0",
      "supplier": {
        "name": "Your Tool Vendor"
      }
    }
  ]
}

3. Component suppliers — the tricky one

Every entry in the components array needs a supplier.name. But where does that data come from if the lockfile doesn't have it?

There are two approaches:

Option A: Registry enrichment (ideal, slower)

Call the npm registry API (https://registry.npmjs.org/{package}) for each dependency, extract the author or publisher, and populate the supplier. This gives you the most accurate data but adds network calls and latency to your SBOM generation pipeline.

Option B: Heuristic from package scope (practical, fast)

For npm packages, the scope (the @org/ prefix) is a reasonable proxy for the supplier. For example:

  • @angular/core → supplier: @angular
  • @types/node → supplier: @types
  • express → supplier: express

This is the approach used by tools like Syft and Trivy. It's not perfect — an unscoped package like express gets attributed to itself — but it satisfies the NTIA requirement and is a defensible choice for automated tooling. The scope genuinely represents the organizational entity that published the package.

Upgrading to CycloneDX 1.7

While you're fixing supplier fields, it's worth upgrading your spec version. CycloneDX 1.7 (released October 2025) is the latest version and is fully backward compatible. The changes are minimal:

{
  "bomFormat": "CycloneDX",
  "specVersion": "1.7",
  "$schema": "http://cyclonedx.org/schema/bom-1.7.schema.json"
}

After the fix

With supplier fields populated at every level, your SBOM should pass all NTIA minimum element checks:

✓ 12/12 NTIA minimum element checks passed

How Verimu handles this

Every SBOM generated by Verimu already includes supplier fields at all three levels — metadata.supplier, metadata.component.supplier, and per-component supplier — using scope-based heuristics for npm packages (with registry enrichment planned for a future release).

Our SBOMs are generated against the CycloneDX 1.7 specification and validated against NTIA minimum elements before delivery. If you're working toward CRA compliance for EU market access by September 2026, this is one less thing to worry about.

Get started free → or book a demo to see how Verimu handles SBOM generation for your stack.