{"record":{"id":"246bb25378ab4138","repo":"badges/shields","slug":"no-public-goals","errorCode":null,"errorMessage":"no public goals","messagePattern":"no public goals","errorType":"exception","errorClass":"InvalidResponse","httpStatus":null,"severity":"warning","filePath":"services/liberapay/liberapay-goal.service.js","lineNumber":30,"sourceCode":"        parameters: pathParams({\n          name: 'entity',\n          example: 'Changaco',\n        }),\n      },\n    },\n  }\n\n  static render({ percentAchieved }) {\n    return {\n      label: 'goal progress',\n      message: `${percentAchieved}%`,\n      color: colorScale([0, 10, 100])(percentAchieved),\n    }\n  }\n\n  transform({ goal, receiving }) {\n    if (!goal) {\n      throw new InvalidResponse({ prettyMessage: 'no public goals' })\n    }\n\n    if (!receiving) {\n      return { percentAchieved: 0 }\n    }\n\n    const percentAchieved = Math.round((receiving.amount / goal.amount) * 100)\n\n    return { percentAchieved }\n  }\n\n  async handle({ entity }) {\n    const { goal, receiving } = await this.fetch({ entity })\n    const { percentAchieved } = this.transform({ goal, receiving })\n    return this.constructor.render({ percentAchieved })\n  }\n}\n","sourceCodeStart":12,"sourceCodeEnd":48,"githubUrl":"https://github.com/badges/shields/blob/766fd8bc89a90b8534dc573ab72dec30215ab1ec/services/liberapay/liberapay-goal.service.js#L12-L48","documentation":"The Liberapay goal badge throws InvalidResponse when the transform receives a falsy `goal` value, meaning the Liberapay API returned no public goal for the account. Users may not have set a funding goal, or hide it; without a goal there is no progress to chart. `receiving` being absent is handled separately (renders 0%), so only the missing goal itself is fatal.","triggerScenarios":"Requesting /liberapay/goal/<entity> where the API response for that account contains no `goal` object — account has no public fundraising goal configured.","commonSituations":"Liberapay profile without a goal set on the profile page; goal privacy enabled; typo'd username pointing at an account with no goal; goal removed after initially displaying.","solutions":["Set a public goal on your Liberapay profile page (Edit profile → Goal) if you own the account.","Check the username in the badge URL matches the Liberapay account that has a goal.","If the account intentionally has no goal, use a different Liberapay badge (receives/gives)."],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"const res = await fetch(`https://liberapay.com/${entity}/public.json`);\nconst data = await res.json();\nif (!data.goal) console.warn(`${entity} has no public goal; use another badge`);","typeGuard":"function hasPublicGoal(data) {\n  return Boolean(data?.goal && typeof data.goal === 'object');\n}","tryCatchPattern":"try {\n  badge = await getLiberapayGoalBadge(entity);\n} catch (e) {\n  if (e.name === 'InvalidResponse') {\n    badge = renderBadge('goal', 'no goal set');\n  } else throw e;\n}","preventionTips":["Set a public goal on the Liberapay profile before adding a goal badge","Fall back to the receives or gives badge when no goal exists","Verify the username matches the account with the goal configured"],"tags":["liberapay","goal","invalid-response","missing-data"],"backgroundTag":"upstream-data-hidden-or-missing","analyzedSha":"766fd8bc89a90b8534dc573ab72dec30215ab1ec","analyzedAt":"2026-08-30T01:40:27.499Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}