ruvnet/ruflo · error · Error
Failed to get bulk ratings
Error message
Failed to get bulk ratings
What it means
Thrown by getBulkRatings() when the POST to publish-registry?action=bulk-ratings returns non-2xx. This call has the longest budget in the file (AbortSignal.timeout(15000)) because it ships up to 50 IDs, so hitting this error means the server answered within 15s but with an error status. No response body is surfaced.
Source
Thrown at v3/@claude-flow/cli/src/services/registry-api.ts:143
throw new Error(`Invalid item ID: ${id}`);
}
}
// Limit batch size
const limitedIds = itemIds.slice(0, 50);
const response = await fetch(`${REGISTRY_API_URL}?action=bulk-ratings`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
itemIds: limitedIds,
itemType,
}),
signal: AbortSignal.timeout(15000),
});
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>;View on GitHub (pinned to fa13ee4ad6)
Solutions
- Retry with backoff (safe read-only operation), then fall back to per-item getRating() calls or an empty result.
- Reduce batch size (e.g. 25 per call) to shrink the payload and narrow server-side failures.
- Cache bulk results with a TTL and refresh in the background instead of per-request.
- Check the itemId list for correctness — server-side rejection of itemType or unknown IDs only surfaces as this generic error.
Example fix
// before
const all = await getBulkRatings(ids); // single point of failure
// after
async function bulkRatingsSafe(ids: string[]): Promise<BulkRatingsResponse> {
try {
return await getBulkRatings(ids.slice(0, 50));
} catch {
const out: BulkRatingsResponse = {};
for (const id of ids) out[id] = { average: 0, count: 0 };
return out;
}
} Defensive patterns
Strategy: retry
Try / catch
async function bulkRatingsResilient(ids: string[]): Promise<BulkRatingsResponse> {
const out: BulkRatingsResponse = {};
for (let i = 0; i < ids.length; i += 50) {
const chunk = ids.slice(i, i + 50);
for (let attempt = 0; ; attempt++) {
try { Object.assign(out, await getBulkRatings(chunk)); break; }
catch (e) {
if (e instanceof Error && e.message.startsWith('Invalid item ID')) throw e; // fix input, don't retry
if (attempt >= 2) { chunk.forEach(id => (out[id] = { average: 0, count: 0 })); break; }
await new Promise(r => setTimeout(r, 400 * 2 ** attempt));
}
}
}
return out;
} Prevention
- Chunk to ≤50 IDs per call — smaller payloads fail less and isolate faults.
- Cache bulk results with a TTL; refresh in the background rather than per request.
- Never retry 'Invalid item ID' errors (error 424) — retrying validation failures just burns quota.
- Ship a zero-value fallback shape so dashboards survive registry outages.
When it happens
Trigger: Server rejects the batch payload (unknown itemType, oversized list server-side), returns 429 under rate limiting, or 5xx during cold start; a proxy intercepts the POST; intermittent failures appear only with large batches near the 50-item cap.
Common situations: Dashboard fetching ratings for dozens of plugins every page load and tripping quotas; a registry deploy temporarily breaking the bulk action; environments where only small POSTs pass a WAF/body-size filter.
Related errors
- Failed to get ratings
- Rating failed: ${error}
- Failed to get analytics
- 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/8893e6bfa48857e9.
Report an issue: GitHub.