badges/shields · warning · InvalidResponse
invalid null license
Error message
invalid null license
What it means
The crates.io license badge service throws InvalidResponse with prettyMessage 'invalid null license' in CratesLicense.transform when the resolved version object from the crates.io API response has no `license` field (null/undefined/empty). This means the upstream API returned data the service cannot render a license badge from.
Source
Thrown at services/crates/crates-license.service.js:42
{
name: 'crate',
example: 'rustc-serialize',
},
{
name: 'version',
example: '0.3.24',
},
),
},
},
}
static defaultBadgeData = { label: 'license', color: 'blue' }
static transform(response) {
const license = this.getVersionObj(response).license
if (!license) {
throw new InvalidResponse({ prettyMessage: 'invalid null license' })
}
return { license }
}
async handle({ crate, version }) {
const json = await this.fetch({ crate, version })
const { license } = this.constructor.transform(json)
return { message: license }
}
}
View on GitHub (pinned to 766fd8bc89)
Solutions
- Verify the crate name and version in the badge URL are correct and the version exists on crates.io
- Check crates.io directly (https://crates.io/api/v1/crates/<crate>/<version>) to confirm `license` is present for that version
- Omit the version parameter to use the latest version, which is more likely to have a license
- If you maintain the crate, add a `license` field to Cargo.toml and publish a new version
Example fix
// before /badge/crates/license/my-old-crate/0.1.0 -> invalid null license // after /badge/crates/license/my-old-crate (use latest version that declares a license)
Defensive patterns
Strategy: validation
Validate before calling
async function hasLicense(crate, version) {
const url = `https://crates.io/api/v1/crates/${crate}${version ? '/' + version : ''}`
const res = await fetch(url, { headers: { 'User-Agent': 'badge-check' } })
if (!res.ok) return false
const data = await res.json()
const v = version ? data.versions?.find(x => x.num === version) : data.versions?.[0]
return Boolean(v?.license)
} Type guard
function hasLicense(v) {
return typeof v?.license === 'string' && v.license.length > 0
} Try / catch
try {
const badge = await getCratesLicenseBadge(crate, version)
} catch (err) {
if (err.prettyMessage === 'invalid null license') {
badge = 'license unknown'
} else throw err
} Prevention
- Verify the crate version declares a license on crates.io before requesting the badge
- Prefer badge URLs without an explicit version so the latest licensed version is used
- Keep Cargo.toml `license` filled when publishing your own crates
- Handle the 'license unknown' fallback in your README badge pipeline
When it happens
Trigger: Requesting a license badge for a crate whose version entry (default or specified via ?version=) has no `license` key in its crates.io API response - e.g. versions published before license metadata was required, or a version that doesn't exist so getVersionObj falls back to an object without license.
Common situations: Very old crates published before crates.io mandated a license field; querying a specific old version; typos in the crate name or version leading to a partial/empty version object.
Related errors
- unknown
- not specified
- version not found
- recent downloads not supported for specific versions
- invalid response data
AI-assisted analysis of badges/shields@766fd8bc89 (2026-08-30).
Data as JSON: /api/errors/e39e1c241cbb05e1.
Report an issue: GitHub.