ruvnet/ruflo · error · Error
Failed to get analytics
Error message
Failed to get analytics
What it means
Thrown by getAnalytics() when the GET to publish-registry?action=analytics returns non-2xx. It is the simplest endpoint in the client (no parameters, 10s timeout), so a failure here usually indicates the registry service itself or the network path, not your inputs. No response body is included.
Source
Thrown at v3/@claude-flow/cli/src/services/registry-api.ts:158
});
if (!response.ok) {
throw new Error('Failed to get bulk ratings');
}
return response.json() as Promise<BulkRatingsResponse>;
}
/**
* Get analytics data
*/
export async function getAnalytics(): Promise<AnalyticsResponse> {
const response = await fetch(`${REGISTRY_API_URL}?action=analytics`, {
signal: AbortSignal.timeout(10000),
});
if (!response.ok) {
throw new Error('Failed to get analytics');
}
return response.json() as Promise<AnalyticsResponse>;
}
/**
* Track a download event
*/
export async function trackDownload(pluginId: string): Promise<void> {
if (!validateItemId(pluginId)) {
return; // Silently fail for invalid IDs
}
try {
await fetch(`${REGISTRY_API_URL}?action=track-download`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ pluginId }),View on GitHub (pinned to fa13ee4ad6)
Solutions
- Retry with exponential backoff on transient statuses, then degrade gracefully — analytics is telemetry, not a dependency.
- Fall back to zeros ({ downloads: {}, exports: 0, imports: 0, publishes: 0 }) or cached last-known values.
- Lengthen your polling interval or cache responses to stay under rate limits.
- Verify with curl whether the endpoint is down for everyone (action=analytics needs no auth/params) before debugging code.
Example fix
// before
const analytics = await getAnalytics(); // throws, breaks the dashboard
// after
const EMPTY: AnalyticsResponse = { downloads: {}, exports: 0, imports: 0, publishes: 0 };
let cached: AnalyticsResponse = EMPTY;
async function analyticsSafe(): Promise<AnalyticsResponse> {
try { return (cached = await getAnalytics()); }
catch { return cached; }
} Defensive patterns
Strategy: retry
Try / catch
const EMPTY: AnalyticsResponse = { downloads: {}, exports: 0, imports: 0, publishes: 0 };
async function analyticsResilient(): Promise<AnalyticsResponse> {
for (let attempt = 0; ; attempt++) {
try { return await getAnalytics(); }
catch (e) {
if (attempt >= 2) return EMPTY;
await new Promise(r => setTimeout(r, 500 * 2 ** attempt));
}
}
} Prevention
- Never make analytics load-bearing: render from cache/zeroes when the endpoint errors.
- Poll on a long interval (minutes) with jitter to stay clear of rate limits.
- Smoke-test the endpoint with curl (action=analytics needs no params) to separate outages from code bugs.
- Record failures with a counter — a rising error rate means registry-side trouble, not yours.
When it happens
Trigger: Cloud Function outage/cold-start 5xx, rate limiting (429), or an intermediary (proxy, captive portal, firewall) answering with an error status for the analytics action.
Common situations: Status dashboards polling analytics on a timer and hitting quotas; CI smoke tests that treat analytics availability as a gate; running behind corporate proxies during registry maintenance windows.
Related errors
- Rating failed: ${error}
- Failed to get ratings
- Failed to get bulk ratings
- Failed to fetch ${baseURL}/models: ${response.status} ${resp
- Failed to fetch manifest from ${url}: ${res.status} ${res.st
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/84fc09e3c26cef41.
Report an issue: GitHub.