jackwener/OpenCLI · error · CliError

FETCH_ERROR

FETCH_ERROR

Error message

FETCH_ERROR: Unable to reach Apple Podcasts charts for ${country.toUpperCase()}

What it means

Thrown by `apple-podcasts top` as a CliError with code FETCH_ERROR when the HTTP request to Apple's charts RSS/API fails at the network level (fetch rejects before a response is received). The message includes the country and the underlying cause (error.cause.code or message) to help diagnose. It covers DNS failures, timeouts (AbortSignal.timeout), TLS errors, and connection resets.

Source

Thrown at clis/apple-podcasts/top.js:30

    browser: false,
    args: [
        { name: 'limit', type: 'int', default: 20, help: 'Number of podcasts (max 100)' },
        { name: 'country', default: 'us', help: 'Country code (e.g. us, cn, gb, jp)' },
    ],
    columns: ['rank', 'title', 'author', 'id'],
    func: async (args) => {
        const limit = Math.max(1, Math.min(Number(args.limit), 100));
        const country = String(args.country || 'us').trim().toLowerCase();
        const url = `${CHARTS_URL}/${country}/podcasts/top/${limit}/podcasts.json`;
        let resp;
        try {
            resp = await fetch(url, {
                signal: AbortSignal.timeout(CHARTS_TIMEOUT_MS),
            });
        }
        catch (error) {
            const reason = error?.cause?.code ?? error?.message ?? 'unknown network error';
            throw new CliError('FETCH_ERROR', `Unable to reach Apple Podcasts charts for ${country.toUpperCase()}`, `Apple charts may be temporarily unavailable (${reason}). Try again later.`);
        }
        if (!resp.ok)
            throw new CliError('FETCH_ERROR', `Charts API HTTP ${resp.status}`, `Check country code: ${country}`);
        const data = await resp.json();
        const results = data?.feed?.results;
        if (!results?.length)
            throw new CliError('NOT_FOUND', 'No chart data found', `Try a different country code`);
        return results.map((p, i) => ({
            rank: i + 1,
            title: p.name,
            author: p.artistName,
            id: p.id,
        }));
    },
});

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Check basic connectivity (e.g. curl https://itunes.apple.com) and retry after transient failures
  2. Verify the timeout is adequate for your network or raise CHARTS_TIMEOUT_MS if configurable
  3. Check proxy/VPN/firewall settings that may block itunes.apple.com; the error's reason field names the underlying code
  4. Confirm Apple's charts service status; try a different country code to isolate a regional outage

Example fix

// before
resp = await fetch(url, {});  // no timeout handling
// after
try {
  resp = await fetch(url, { signal: AbortSignal.timeout(CHARTS_TIMEOUT_MS) });
} catch (error) {
  // retry once, then surface CliError('FETCH_ERROR', ...) with error?.cause?.code
}
Defensive patterns

Strategy: retry

Validate before calling

// Cheap pre-flight: is the endpoint reachable at all?
const probe = await fetch('https://itunes.apple.com/', { signal: AbortSignal.timeout(5000) })
  .then((r) => r.ok).catch(() => false);
if (!probe) console.log('Network cannot reach itunes.apple.com; fix connectivity before running top.');

Try / catch

try {
  await cli.run(['apple-podcasts', 'top', '--country', 'us']);
} catch (e) {
  if (e.code === 'FETCH_ERROR' && /Unable to reach/.test(e.message)) {
    await new Promise((r) => setTimeout(r, 2000));
    // retry once or surface with e.hint's reason
  } else throw e;
}

Prevention

When it happens

Trigger: `opencli apple-podcasts top --country <cc>` where fetch(url, { signal: AbortSignal.timeout(CHARTS_TIMEOUT_MS) }) rejects — timeout exceeded, DNS failure, offline network, or proxy blocking itunes.apple.com.

Common situations: Offline or firewalled network; corporate proxy blocking Apple domains; charts endpoint temporarily down; CHARTS_TIMEOUT_MS too low on a slow connection.

Related errors


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