jackwener/OpenCLI · error · EmptyResultError
homebrew popular
Error message
homebrew popular
What it means
brewFetch wraps any fetch/transport failure for the analytics request in CommandExecutionError labeled 'homebrew popular'. The label is also the fallback context string passed when the Homebrew analytics endpoint (formulae.brew.sh) cannot be reached, returns a non-OK status, or responds with malformed JSON.
Source
Thrown at clis/homebrew/popular.js:38
domain: 'formulae.brew.sh',
strategy: Strategy.PUBLIC,
browser: false,
args: [
{ name: 'type', default: 'formula', help: `Package type (${TYPES.join(' / ')})` },
{ name: 'window', default: '30d', help: `Time window (${WINDOWS.join(' / ')})` },
{ name: 'limit', type: 'int', default: 30, help: 'Max rows (1-500)' },
],
columns: ['rank', 'token', 'type', 'installs', 'percent', 'window', 'url'],
func: async (args) => {
const type = requireOneOf(args.type, TYPES, 'type');
const window = requireOneOf(args.window, WINDOWS, 'window');
const limit = requireBoundedInt(args.limit, 30, 500);
const path = type === 'cask' ? 'cask-install' : 'install';
const url = `${BREW_BASE}/analytics/${path}/${window}.json`;
const body = await brewFetch(url, 'homebrew popular');
const items = Array.isArray(body?.items) ? body.items : [];
if (!items.length) {
throw new EmptyResultError('homebrew popular', `Homebrew analytics returned no items for ${type}/${window}.`);
}
return items.slice(0, limit).map((row, i) => {
const token = String(type === 'cask' ? row.cask : row.formula ?? '').trim();
const detailPath = type === 'cask' ? 'cask' : 'formula';
return {
rank: row.number != null ? Number(row.number) : i + 1,
token,
type,
installs: parseInstallCount(row.count),
percent: row.percent != null ? Number(row.percent) : null,
window,
url: token ? `https://formulae.brew.sh/${detailPath}/${encodeURIComponent(token)}` : '',
};
});
},
});
View on GitHub (pinned to 49907e53dc)
Solutions
- Check network reachability of https://formulae.brew.sh from this machine
- Retry after a short wait — the API is static GitHub Pages and outages are brief
- Check proxy/firewall settings if behind a corporate network
- Catch CommandExecutionError and fall back to cached/last-known analytics data
Example fix
// before
const body = await brewFetch(url, 'homebrew popular');
// after
let body;
try {
body = await brewFetch(url, 'homebrew popular');
} catch (err) {
body = await readCachedAnalytics() ?? throwWith Hint(err);
} Defensive patterns
Strategy: retry
Validate before calling
const url = `${BREW_BASE}/analytics/${path}/${window}.json`;
const head = await fetch(url, { method: 'HEAD' }).catch(() => null);
if (!head || !head.ok) throw new Error(`formulae.brew.sh unreachable (status ${head?.status ?? 'network error'})`); Try / catch
async function fetchWithRetry(url, label, retries = 3) {
for (let i = 0; i < retries; i++) {
try {
return await brewFetch(url, label);
} catch (err) {
if (i === retries - 1) throw err;
await new Promise(r => setTimeout(r, 1000 * 2 ** i));
}
}
} Prevention
- Retry with exponential backoff — the API is static GitHub Pages and briefly flaky
- Cache the last successful analytics JSON as a fallback
- Check DNS/proxy config in CI before scraping
- Respect the bundled user-agent and avoid hammering the endpoint
When it happens
Trigger: The GET to `${BREW_BASE}/analytics/install|cask-install/<window>.json` throws a network error, returns HTTP != 200/404/429, or the body fails JSON.parse.
Common situations: Offline or corporate-proxy-blocked network, formulae.brew.sh (GitHub Pages) outage, transient 5xx, or DNS failure in CI containers.
Understand the failure class
Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.
Related errors
- 12306 queryByTrainNo returned HTTP ${resp.status}
- 12306 queryByTrainNo returned non-JSON body
- 12306 ${endpoint} returned non-JSON body
- 1point3acres request failed: HTTP ${res.status} ${res.status
- ${label} returned HTTP ${resp.status}: ${summarizeApiError(p
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/0dd7f3ed33e753c7.
Report an issue: GitHub.