jackwener/OpenCLI · warning · CommandExecutionError

hf spaces returned HTTP 429 (rate limited)

Error message

hf spaces returned HTTP 429 (rate limited)

What it means

The Hugging Face Spaces API responded with HTTP 429 Too Many Requests, meaning the server is rate-limiting this client. The library detects status 429 explicitly and appends guidance: Hugging Face throttles unauthenticated traffic, so wait and retry.

Source

Thrown at clis/hf/spaces.js:65

        const url = new URL('https://huggingface.co/api/spaces');
        url.searchParams.set('sort', sort);
        url.searchParams.set('direction', '-1');
        url.searchParams.set('limit', String(limit));
        url.searchParams.set('full', 'true');
        if (args.search) url.searchParams.set('search', String(args.search));
        if (sdk) url.searchParams.set('sdk', sdk);

        let resp;
        try {
            resp = await fetch(url, {
                headers: { Accept: 'application/json', 'User-Agent': 'opencli/1.0 (+https://github.com/jackwener/opencli)' },
            });
        }
        catch (err) {
            throw new CommandExecutionError(`hf spaces request failed: ${err?.message ?? err}`);
        }
        if (resp.status === 429) {
            throw new CommandExecutionError(
                'hf spaces returned HTTP 429 (rate limited)',
                'Hugging Face throttles unauthenticated traffic; wait a few seconds and retry.',
            );
        }
        if (!resp.ok) {
            throw new CommandExecutionError(`hf spaces failed: HTTP ${resp.status}`);
        }
        let data;
        try {
            data = await resp.json();
        }
        catch (err) {
            throw new CommandExecutionError(`hf spaces returned malformed JSON: ${err?.message ?? err}`);
        }
        const list = Array.isArray(data) ? data : [];
        if (!list.length) {
            throw new EmptyResultError('hf spaces', 'No matching spaces on huggingface.co.');
        }

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Wait a few seconds and retry with exponential backoff
  2. Authenticate requests with an HF token (Authorization: Bearer hf_...) to get a higher rate limit
  3. Add spacing/jitter between repeated calls or cache results
  4. Reduce polling frequency in scripts/CI

Example fix

// before: tight loop hammering the API
for (const q of queries) await listSpaces(q);
// after
for (const q of queries) {
  await listSpaces(q);
  await new Promise((r) => setTimeout(r, 2000));
}
Defensive patterns

Strategy: retry

Validate before calling

// throttle your own calls: simple client-side rate limiter
let last = 0;
async function throttled(fn, minGapMs = 2000) {
  const wait = last + minGapMs - Date.now();
  if (wait > 0) await new Promise(r => setTimeout(r, wait));
  last = Date.now();
  return fn();
}

Try / catch

async function withBackoff(fn, tries = 4) {
  for (let i = 0; i < tries; i++) {
    try { return await fn(); }
    catch (e) {
      if (!String(e.message).includes('429') || i === tries - 1) throw e;
      await new Promise(r => setTimeout(r, 2 ** i * 1000));
    }
  }
}

Prevention

When it happens

Trigger: Calling `hf spaces` (GET /api/spaces) too frequently without authentication, so HF's per-IP anonymous rate limit is exceeded and the server returns 429.

Common situations: Scripts or CI pipelines polling the spaces endpoint in a loop without delays; shared CI runner IPs that are already throttled by HF; bursty retries after other failures.

Understand the failure class

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/06a556ece6353c80. Report an issue: GitHub.