{"record":{"id":"e39e1c241cbb05e1","repo":"badges/shields","slug":"invalid-null-license","errorCode":null,"errorMessage":"invalid null license","messagePattern":"invalid null license","errorType":"exception","errorClass":"InvalidResponse","httpStatus":null,"severity":"warning","filePath":"services/crates/crates-license.service.js","lineNumber":42,"sourceCode":"          {\n            name: 'crate',\n            example: 'rustc-serialize',\n          },\n          {\n            name: 'version',\n            example: '0.3.24',\n          },\n        ),\n      },\n    },\n  }\n\n  static defaultBadgeData = { label: 'license', color: 'blue' }\n\n  static transform(response) {\n    const license = this.getVersionObj(response).license\n    if (!license) {\n      throw new InvalidResponse({ prettyMessage: 'invalid null license' })\n    }\n\n    return { license }\n  }\n\n  async handle({ crate, version }) {\n    const json = await this.fetch({ crate, version })\n    const { license } = this.constructor.transform(json)\n    return { message: license }\n  }\n}\n","sourceCodeStart":24,"sourceCodeEnd":54,"githubUrl":"https://github.com/badges/shields/blob/766fd8bc89a90b8534dc573ab72dec30215ab1ec/services/crates/crates-license.service.js#L24-L54","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\n/badge/crates/license/my-old-crate/0.1.0  ->  invalid null license\n// after\n/badge/crates/license/my-old-crate  (use latest version that declares a license)","handlingStrategy":"validation","validationCode":"async function hasLicense(crate, version) {\n  const url = `https://crates.io/api/v1/crates/${crate}${version ? '/' + version : ''}`\n  const res = await fetch(url, { headers: { 'User-Agent': 'badge-check' } })\n  if (!res.ok) return false\n  const data = await res.json()\n  const v = version ? data.versions?.find(x => x.num === version) : data.versions?.[0]\n  return Boolean(v?.license)\n}","typeGuard":"function hasLicense(v) {\n  return typeof v?.license === 'string' && v.license.length > 0\n}","tryCatchPattern":"try {\n  const badge = await getCratesLicenseBadge(crate, version)\n} catch (err) {\n  if (err.prettyMessage === 'invalid null license') {\n    badge = 'license unknown'\n  } else throw err\n}","preventionTips":["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"],"tags":["crates-io","license","missing-metadata","upstream-api"],"backgroundTag":"missing-license-metadata","analyzedSha":"766fd8bc89a90b8534dc573ab72dec30215ab1ec","analyzedAt":"2026-08-30T01:40:27.499Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}