{"record":{"id":"2372ffa6ddfa6960","repo":"ruvnet/ruflo","slug":"rating-failed-error","errorCode":null,"errorMessage":"Rating failed: ${error}","messagePattern":"Rating failed: (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/cli/src/services/registry-api.ts","lineNumber":81,"sourceCode":"  if (!validateRating(rating)) {\n    throw new Error('Rating must be integer 1-5');\n  }\n\n  const response = await fetch(`${REGISTRY_API_URL}?action=rate`, {\n    method: 'POST',\n    headers: { 'Content-Type': 'application/json' },\n    body: JSON.stringify({\n      itemId,\n      rating,\n      itemType,\n      ...(userId && { userId }),\n    }),\n    signal: AbortSignal.timeout(10000),\n  });\n\n  if (!response.ok) {\n    const error = await response.text();\n    throw new Error(`Rating failed: ${error}`);\n  }\n\n  return response.json() as Promise<RatingResponse>;\n}\n\n/**\n * Get ratings for a single item\n */\nexport async function getRating(\n  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',","sourceCodeStart":63,"sourceCodeEnd":99,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/cli/src/services/registry-api.ts#L63-L99","documentation":"Thrown by rateItem() when the POST to https://us-central1-claude-flow.cloudfunctions.net/publish-registry?action=rate returns a non-2xx status. The raw response body text is embedded in the message, so the Cloud Function's own error (validation, quota, auth) is visible after the 'Rating failed: ' prefix. Note the fetch itself already enforces a 10s AbortSignal timeout, so this error means the server was reached but rejected the request.","triggerScenarios":"The Cloud Function returns 4xx for a payload its side rejects (unknown itemId, wrong itemType, malformed userId) or 5xx during a cold start / outage; a corporate proxy or captive portal returns 403/502; the endpoint is rate-limiting your client.","commonSituations":"CI environments with restricted egress where the proxy answers with an HTML error page (that HTML ends up in the message); rating an itemId that was never published to the registry; Google Cloud Functions cold-start 500s; running during a registry deploy outage.","solutions":["Read the text after 'Rating failed: ' — it is the server's response body and names the actual cause (e.g. 'item not found', 'quota exceeded').","Retry transient 5xx/502/503 with exponential backoff (the fetch already times out at 10s per attempt); do not retry 4xx.","Verify the itemId exists in the registry (it must have been published, not just installed locally) and that itemType is 'plugin' or 'model'.","Check network egress: curl -i 'https://us-central1-claude-flow.cloudfunctions.net/publish-registry?action=analytics' — if a proxy page comes back, fix the environment, not the code."],"exampleFix":"// before\ntry {\n  await rateItem(pluginId, 5);\n} catch (e) {\n  throw e; // 'Rating failed: <html>Proxy Error...' — opaque\n}\n\n// after\ntry {\n  await rateItem(pluginId, 5);\n} catch (e) {\n  const msg = e instanceof Error ? e.message : String(e);\n  if (msg.startsWith('Rating failed: ') && /5\\d{2}|quota/i.test(msg)) {\n    await backoffRetry(() => rateItem(pluginId, 5), { tries: 3 });\n  } else {\n    throw e;\n  }\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  return await rateItem(itemId, rating);\n} catch (e) {\n  const msg = e instanceof Error ? e.message : String(e);\n  if (!msg.startsWith('Rating failed: ')) throw e; // client-side validation → fix input\n  const serverText = msg.slice('Rating failed: '.length);\n  if (/^5\\d{2}|quota|rate/i.test(serverText)) {\n    return backoffRetry(() => rateItem(itemId, rating), { tries: 3, baseMs: 500 });\n  }\n  throw new Error(`Registry rejected rating: ${serverText}`, { cause: e });\n}","preventionTips":["Treat ratings as best-effort telemetry: catch and log, never let a failed rating break the user flow.","Verify egress to *.cloudfunctions.net in CI/prod environments (proxy errors appear verbatim in the message).","Cache the rating UI locally and sync once, instead of posting on every interaction.","Distinguish client validation errors ('Rating must be integer 1-5', 'Invalid item ID') from server text by message prefix before retrying — only the latter can be transient."],"tags":["network","http","rating","registry-api","cloud-functions"],"backgroundTag":"http-request-failed","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}