{"record":{"id":"d8bbfcc68fd37b29","repo":"badges/shields","slug":"invalid-url","errorCode":null,"errorMessage":"invalid url","messagePattern":"invalid url","errorType":"validation","errorClass":"InvalidParameter","httpStatus":400,"severity":"error","filePath":"services/endpoint/endpoint.service.js","lineNumber":190,"sourceCode":"      ),\n    }\n  }\n\n  constructor(...args) {\n    super(...args)\n    const config = configModule.util.toObject()\n    this._allowUnsecuredEndpointRequests =\n      config?.public?.allowUnsecuredEndpointRequests || false\n  }\n\n  async handle(namedParams, { url }) {\n    let protocol, hostname\n    try {\n      const parsedUrl = new URL(url)\n      protocol = parsedUrl.protocol\n      hostname = parsedUrl.hostname\n    } catch (e) {\n      throw new InvalidParameter({ prettyMessage: 'invalid url' })\n    }\n    if (protocol !== 'https:' && !this._allowUnsecuredEndpointRequests) {\n      throw new InvalidParameter({ prettyMessage: 'please use https' })\n    }\n    if (blockedDomains.some(domain => hostname.endsWith(domain))) {\n      throw new InvalidParameter({ prettyMessage: 'domain is blocked' })\n    }\n\n    const validated = await fetchEndpointData(this, {\n      url,\n      httpErrors,\n      validationPrettyErrorMessage: 'invalid properties',\n      includeKeys: true,\n    })\n\n    return this.constructor.render(validated)\n  }\n}","sourceCodeStart":172,"sourceCodeEnd":208,"githubUrl":"https://github.com/badges/shields/blob/766fd8bc89a90b8534dc573ab72dec30215ab1ec/services/endpoint/endpoint.service.js#L172-L208","documentation":"The endpoint badge service validates the user-supplied url with new URL() before making a request. If parsing fails (malformed URL string), it throws InvalidParameter with prettyMessage 'invalid url'. This is an input-validation error on the badge query parameter, not a network failure.","triggerScenarios":"GET /badge/endpoint with a json?url= parameter that is not a parseable absolute URL: missing scheme, spaces or unencoded special characters, relative paths, or an empty url parameter.","commonSituations":"Forgetting https:// prefix; passing URLs with raw ampersands/quotes not URL-encoded in the badge link; configuration templates leaving the url placeholder unfilled.","solutions":["Ensure the url parameter is a full absolute URL including scheme (https://...)","URL-encode the url value (encodeURIComponent) when embedding it in a badge link","Test the URL with new URL(url) locally to confirm it parses","Remove trailing whitespace or stray characters from the configured URL"],"exampleFix":"// before\n/badge/endpoint?url=api.example.com/data.json\n// after\n/badge/endpoint?url=https%3A%2F%2Fapi.example.com%2Fdata.json","handlingStrategy":"validation","validationCode":"function isValidBadgeUrl(url) {\n  try {\n    const u = new URL(url)\n    return Boolean(u.protocol && u.hostname)\n  } catch {\n    return false\n  }\n}\n// if (!isValidBadgeUrl(cfg.url)) fix the URL before building the badge link","typeGuard":"function isParsedUrl(url) {\n  try { new URL(url); return true } catch { return false }\n}","tryCatchPattern":"try {\n  const badge = await getEndpointBadge({ url: cfg.url })\n} catch (e) {\n  if (e.prettyMessage === 'invalid url') {\n    console.error(`Malformed endpoint URL: ${cfg.url}`)\n  } else throw e\n}","preventionTips":["Always include the scheme (https://) in endpoint badge URLs","URL-encode the url query-parameter value when embedding in badge links","Lint config templates for unfilled URL placeholders","Test new URL(value) locally for every configured badge URL"],"tags":["url","validation","invalid-parameter","endpoint-badge"],"backgroundTag":"invalid-url-parameter","analyzedSha":"766fd8bc89a90b8534dc573ab72dec30215ab1ec","analyzedAt":"2026-08-30T01:40:27.499Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}