koala73/worldmonitor · error · Error

Wikidata request failed with status ${response.status}

Error message

Wikidata request failed with status ${response.status}

What it means

queryWikidata fetches country facts from the Wikidata SPARQL/REST endpoint with WIKIDATA_ATTEMPTS tries. Retryable failures (429 or 5xx) are retried, but when the final attempt still returns a non-ok status — or the status is non-retryable like 400/403/404 — it throws Error 'Wikidata request failed with status <status>'. This surfaces upstream Wikidata rejection to the country-facts caller.

Source

Thrown at server/worldmonitor/intelligence/v1/get-country-facts.ts:167

async function queryWikidata(sparql: string): Promise<WikidataBinding[]> {
  const url = `https://query.wikidata.org/sparql?format=json&query=${encodeURIComponent(sparql)}`;

  for (let attempt = 0; attempt < WIKIDATA_ATTEMPTS; attempt += 1) {
    let response: Response;
    try {
      response = await fetch(url, {
        headers: { 'User-Agent': WIKIMEDIA_UA, Accept: 'application/json' },
        signal: AbortSignal.timeout(UPSTREAM_TIMEOUT),
      });
    } catch (error) {
      if (attempt === WIKIDATA_ATTEMPTS - 1) throw error;
      continue;
    }
    if (!response.ok) {
      const retryable = response.status === 429 || response.status >= 500;
      if (retryable && attempt < WIKIDATA_ATTEMPTS - 1) continue;
      throw new Error(`Wikidata request failed with status ${response.status}`);
    }

    try {
      const data = (await response.json()) as WikidataResponse;
      return data.results?.bindings ?? [];
    } catch (error) {
      if (attempt === WIKIDATA_ATTEMPTS - 1) throw error;
    }
  }

  throw new Error('Wikidata request failed');
}

function parseWikidataFacts(bindings: WikidataBinding[]): WikiResult | null {
  if (bindings.length === 0) return null;

  const firstLabel = (field: keyof WikidataBinding): string => {
    for (const binding of bindings) {

View on GitHub (pinned to 9361220cc0)

Solutions

  1. Check the status in the message: 400 means fix the query, 403 means fix the User-Agent, 429 means back off, 5xx means retry later or check Wikidata status
  2. Increase WIKIDATA_ATTEMPTS or add exponential backoff between attempts for sustained 429/5xx
  3. Ensure requests send a descriptive User-Agent header per Wikimedia UA policy
  4. Add a fallback path (cached facts or a second data source) so country facts survive Wikidata unavailability

Example fix

// before
throw new Error(`Wikidata request failed with status ${response.status}`);
// after
const body = await response.text().catch(() => '');
logger.warn('wikidata failed', response.status, body.slice(0, 200));
throw new Error(`Wikidata request failed with status ${response.status}`);
Defensive patterns

Strategy: retry

Validate before calling

// Validate request inputs before hitting Wikidata
if (!countryCode || !/^[A-Z]{2}$/.test(countryCode)) throw new Error('invalid country code');

Type guard

function isWikidataStatusError(e: unknown): e is Error & { status?: number } {
  return e instanceof Error && /^Wikidata request failed with status \d+$/.test(e.message);
}

Try / catch

try {
  bindings = await queryWikidata(sparql);
} catch (e) {
  if (isWikidataStatusError(e) && /status (429|5\d\d)/.test(e.message)) {
    return serveCachedFacts(countryCode); // stale-but-available
  }
  throw e;
}

Prevention

When it happens

Trigger: The final fetch to the Wikidata endpoint responds with a non-ok status: non-retryable 400/401/403/404 immediately, or a 429/5xx that persists through all WIKIDATA_ATTEMPTS retries.

Common situations: Wikidata rate limiting the server IP (429 sustained); Wikidata outage (502/503) lasting longer than the retry budget; malformed SPARQL query returning 400 after a code change; User-Agent blocked by Wikimedia policy (403).

Related errors


AI-assisted analysis of koala73/worldmonitor@9361220cc0 (2026-09-01). Data as JSON: /api/errors/db1a016fbed1b995. Report an issue: GitHub.