{"record":{"id":"482bc6897690c1a7","repo":"badges/shields","slug":"version-downloads-requires-a-version","errorCode":null,"errorMessage":"version downloads requires a version","messagePattern":"version downloads requires a version","errorType":"validation","errorClass":"InvalidParameter","httpStatus":400,"severity":"error","filePath":"services/gem/gem-downloads.service.js","lineNumber":126,"sourceCode":"  }\n\n  async fetchDownloadCountForGem({ gem }) {\n    const { downloads: totalDownloads, version_downloads: versionDownloads } =\n      await this._requestJson({\n        url: `https://rubygems.org/api/v1/gems/${gem}.json`,\n        schema: gemSchema,\n        httpErrors: {\n          404: 'gem not found',\n        },\n      })\n    return { totalDownloads, versionDownloads }\n  }\n\n  async handle({ variant, gem, version }) {\n    let downloads\n    if (variant === 'dv') {\n      if (!version) {\n        throw new InvalidParameter({\n          prettyMessage: 'version downloads requires a version',\n        })\n      }\n      if (version !== 'stable' && !semver.valid(version)) {\n        throw new InvalidParameter({\n          prettyMessage: 'version should be \"stable\" or valid semver',\n        })\n      }\n      downloads = await this.fetchDownloadCountForVersion({ gem, version })\n    } else {\n      const { totalDownloads, versionDownloads } =\n        await this.fetchDownloadCountForGem({ gem, variant })\n      downloads = variant === 'dtv' ? versionDownloads : totalDownloads\n    }\n    return this.constructor.render({ variant, version, downloads })\n  }\n}\n","sourceCodeStart":108,"sourceCodeEnd":144,"githubUrl":"https://github.com/badges/shields/blob/766fd8bc89a90b8534dc573ab72dec30215ab1ec/services/gem/gem-downloads.service.js#L108-L144","documentation":"Thrown in GemDownloadsService.handle when the 'dv' (downloads per version) variant is requested but no version parameter is supplied. The dv path semantically requires an explicit version, so a missing version is rejected with InvalidParameter 'version downloads requires a version'.","triggerScenarios":"GET /gem/dv/<gem> — the variant is 'dv' but the version URL segment is absent, so handle({ variant: 'dv', gem, version: undefined }).","commonSituations":"Users copying the total-downloads badge URL (/gem/dt/ or /gem/) but keeping or mixing variant tokens, omitting the version segment for dv; documentation confusion between dt (total) and dv (per-version).","solutions":["Add the version segment: /gem/dv/<gem>/<version>","Use the plain downloads badge (/gem/dt/<gem> or /gem/<gem>) if you do not want a specific version","Pass version 'stable' if you want the stable version's downloads"],"exampleFix":"// before\n/gem/dv/mygem\n// after\n/gem/dv/mygem/1.2.3","handlingStrategy":"validation","validationCode":"if (variant === 'dv' && !version) { throw new Error('dv variant requires a version: /gem/dv/<gem>/<version>'); }","typeGuard":"const isDvRequest = (q) => q?.variant === 'dv' && typeof q?.version === 'string' && q.version.length > 0;","tryCatchPattern":"try { return await gemBadge({ variant, gem, version }); } catch (e) { if (String(e.message).includes('requires a version')) { return gemBadge({ variant: 'dt', gem }); } throw e; }","preventionTips":["Always include the version segment when using the dv variant","Use dt (total downloads) when no specific version is needed","Check badge URL templates render all placeholders (no empty segments)"],"tags":["rubygems","invalid-parameter","missing-parameter"],"backgroundTag":"missing-required-parameter","analyzedSha":"766fd8bc89a90b8534dc573ab72dec30215ab1ec","analyzedAt":"2026-08-30T01:40:27.499Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}