{"record":{"id":"3d93abe5f23c1064","repo":"ruvnet/ruflo","slug":"failed-to-get-ratings","errorCode":null,"errorMessage":"Failed to get ratings","messagePattern":"Failed to get ratings","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/cli/src/services/registry-api.ts","lineNumber":109,"sourceCode":"  itemId: string,\n  itemType: 'plugin' | 'model' = 'plugin'\n): Promise<RatingResponse> {\n  if (!validateItemId(itemId)) {\n    throw new Error('Invalid item ID');\n  }\n\n  const params = new URLSearchParams({\n    action: 'get-ratings',\n    itemId,\n    itemType,\n  });\n\n  const response = await fetch(`${REGISTRY_API_URL}?${params}`, {\n    signal: AbortSignal.timeout(10000),\n  });\n\n  if (!response.ok) {\n    throw new Error('Failed to get ratings');\n  }\n\n  return response.json() as Promise<RatingResponse>;\n}\n\n/**\n * Get ratings for multiple items (batch)\n */\nexport async function getBulkRatings(\n  itemIds: string[],\n  itemType: 'plugin' | 'model' = 'plugin'\n): Promise<BulkRatingsResponse> {\n  // Validate all IDs\n  for (const id of itemIds) {\n    if (!validateItemId(id)) {\n      throw new Error(`Invalid item ID: ${id}`);\n    }\n  }","sourceCodeStart":91,"sourceCodeEnd":127,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/cli/src/services/registry-api.ts#L91-L127","documentation":"Thrown by getRating() when the GET to publish-registry?action=get-ratings&itemId=... returns a non-2xx status. Unlike rateItem(), no response body is included in the message, so this is a bare 'the ratings endpoint said no'. The fetch carries a 10s AbortSignal timeout, so reaching this line means the server responded with an error status.","triggerScenarios":"Cloud Function returns 404/500 for an unknown or never-rated itemId (some backends 404 instead of returning count: 0), 429 from rate limiting, or 5xx during cold start; an intermediary proxy returns 4xx/5xx.","commonSituations":"Fetching ratings for a freshly published plugin before any ratings exist; polling the endpoint in a loop and tripping rate limits; CI with proxied egress; regional outage of the us-central1 Cloud Function.","solutions":["Retry with backoff on 5xx/429 — the call is a read, so retrying is safe; treat persistent 404 as 'no ratings yet'.","Wrap the call and fall back to { average: 0, count: 0 } so UI rendering never depends on registry availability.","Cache ratings locally with a TTL instead of fetching on every render; this also keeps you inside rate limits.","Confirm the itemId is registered (it must have been published) — an unpublishable ID yields server errors, not the client-side 'Invalid item ID'."],"exampleFix":"// before\nconst { average } = await getRating(pluginId); // may throw 'Failed to get ratings'\n\n// after\nasync function safeRating(pluginId: string) {\n  for (let attempt = 0; attempt < 3; attempt++) {\n    try {\n      return await getRating(pluginId);\n    } catch (e) {\n      if (attempt === 2) return { success: false, itemId: pluginId, average: 0, count: 0 };\n      await new Promise(r => setTimeout(r, 250 * 2 ** attempt));\n    }\n  }\n  throw new Error('unreachable');\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"const EMPTY = (id: string) => ({ success: false, itemId: id, average: 0, count: 0 });\nasync function getRatingSafe(id: string, tries = 3) {\n  for (let i = 0; ; i++) {\n    try { return await getRating(id); }\n    catch (e) {\n      if (i === tries - 1) return EMPTY(id);          // degrade, don't crash\n      if (e instanceof Error && e.message === 'Invalid item ID') return EMPTY(id); // don't retry client errors\n      await new Promise(r => setTimeout(r, 300 * 2 ** i));\n    }\n  }\n}","preventionTips":["Treat ratings as optional enrichment: always render UI with a 0/0 default.","Cache getRating results with a TTL to avoid hammering the Cloud Function into 429s.","Retry only transient failures with backoff; never retry the 'Invalid item ID' sibling error.","In CI, stub the registry client rather than depending on live network availability."],"tags":["network","http","ratings","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"}