{"record":{"id":"84fc09e3c26cef41","repo":"ruvnet/ruflo","slug":"failed-to-get-analytics","errorCode":null,"errorMessage":"Failed to get analytics","messagePattern":"Failed to get analytics","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/cli/src/services/registry-api.ts","lineNumber":158,"sourceCode":"  });\n\n  if (!response.ok) {\n    throw new Error('Failed to get bulk ratings');\n  }\n\n  return response.json() as Promise<BulkRatingsResponse>;\n}\n\n/**\n * Get analytics data\n */\nexport async function getAnalytics(): Promise<AnalyticsResponse> {\n  const response = await fetch(`${REGISTRY_API_URL}?action=analytics`, {\n    signal: AbortSignal.timeout(10000),\n  });\n\n  if (!response.ok) {\n    throw new Error('Failed to get analytics');\n  }\n\n  return response.json() as Promise<AnalyticsResponse>;\n}\n\n/**\n * Track a download event\n */\nexport async function trackDownload(pluginId: string): Promise<void> {\n  if (!validateItemId(pluginId)) {\n    return; // Silently fail for invalid IDs\n  }\n\n  try {\n    await fetch(`${REGISTRY_API_URL}?action=track-download`, {\n      method: 'POST',\n      headers: { 'Content-Type': 'application/json' },\n      body: JSON.stringify({ pluginId }),","sourceCodeStart":140,"sourceCodeEnd":176,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/cli/src/services/registry-api.ts#L140-L176","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nconst analytics = await getAnalytics(); // throws, breaks the dashboard\n\n// after\nconst EMPTY: AnalyticsResponse = { downloads: {}, exports: 0, imports: 0, publishes: 0 };\nlet cached: AnalyticsResponse = EMPTY;\nasync function analyticsSafe(): Promise<AnalyticsResponse> {\n  try { return (cached = await getAnalytics()); }\n  catch { return cached; }\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"const EMPTY: AnalyticsResponse = { downloads: {}, exports: 0, imports: 0, publishes: 0 };\nasync function analyticsResilient(): Promise<AnalyticsResponse> {\n  for (let attempt = 0; ; attempt++) {\n    try { return await getAnalytics(); }\n    catch (e) {\n      if (attempt >= 2) return EMPTY;\n      await new Promise(r => setTimeout(r, 500 * 2 ** attempt));\n    }\n  }\n}","preventionTips":["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."],"tags":["network","http","analytics","registry-api","cloud-functions"],"backgroundTag":"http-request-failed","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}