badges/shields · warning · InvalidResponse

no public goals

Error message

no public goals

What it means

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.

Source

Thrown at services/liberapay/liberapay-goal.service.js:30

        parameters: pathParams({
          name: 'entity',
          example: 'Changaco',
        }),
      },
    },
  }

  static render({ percentAchieved }) {
    return {
      label: 'goal progress',
      message: `${percentAchieved}%`,
      color: colorScale([0, 10, 100])(percentAchieved),
    }
  }

  transform({ goal, receiving }) {
    if (!goal) {
      throw new InvalidResponse({ prettyMessage: 'no public goals' })
    }

    if (!receiving) {
      return { percentAchieved: 0 }
    }

    const percentAchieved = Math.round((receiving.amount / goal.amount) * 100)

    return { percentAchieved }
  }

  async handle({ entity }) {
    const { goal, receiving } = await this.fetch({ entity })
    const { percentAchieved } = this.transform({ goal, receiving })
    return this.constructor.render({ percentAchieved })
  }
}

View on GitHub (pinned to 766fd8bc89)

Solutions

  1. Set a public goal on your Liberapay profile page (Edit profile → Goal) if you own the account.
  2. Check the username in the badge URL matches the Liberapay account that has a goal.
  3. If the account intentionally has no goal, use a different Liberapay badge (receives/gives).
Defensive patterns

Strategy: fallback

Validate before calling

const res = await fetch(`https://liberapay.com/${entity}/public.json`);
const data = await res.json();
if (!data.goal) console.warn(`${entity} has no public goal; use another badge`);

Type guard

function hasPublicGoal(data) {
  return Boolean(data?.goal && typeof data.goal === 'object');
}

Try / catch

try {
  badge = await getLiberapayGoalBadge(entity);
} catch (e) {
  if (e.name === 'InvalidResponse') {
    badge = renderBadge('goal', 'no goal set');
  } else throw e;
}

Prevention

When it happens

Trigger: Requesting /liberapay/goal/<entity> where the API response for that account contains no `goal` object — account has no public fundraising goal configured.

Common situations: 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.

Related errors


AI-assisted analysis of badges/shields@766fd8bc89 (2026-08-30). Data as JSON: /api/errors/246bb25378ab4138. Report an issue: GitHub.