ruvnet/ruflo · error

Rating failed: ${error}

Error message

Rating failed: ${error}

What it means

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.

Source

Thrown at v3/@claude-flow/cli/src/services/registry-api.ts:81

  if (!validateRating(rating)) {
    throw new Error('Rating must be integer 1-5');
  }

  const response = await fetch(`${REGISTRY_API_URL}?action=rate`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      itemId,
      rating,
      itemType,
      ...(userId && { userId }),
    }),
    signal: AbortSignal.timeout(10000),
  });

  if (!response.ok) {
    const error = await response.text();
    throw new Error(`Rating failed: ${error}`);
  }

  return response.json() as Promise<RatingResponse>;
}

/**
 * Get ratings for a single item
 */
export async function getRating(
  itemId: string,
  itemType: 'plugin' | 'model' = 'plugin'
): Promise<RatingResponse> {
  if (!validateItemId(itemId)) {
    throw new Error('Invalid item ID');
  }

  const params = new URLSearchParams({
    action: 'get-ratings',

View on GitHub (pinned to fa13ee4ad6)

Solutions

  1. 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').
  2. Retry transient 5xx/502/503 with exponential backoff (the fetch already times out at 10s per attempt); do not retry 4xx.
  3. Verify the itemId exists in the registry (it must have been published, not just installed locally) and that itemType is 'plugin' or 'model'.
  4. 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.

Example fix

// before
try {
  await rateItem(pluginId, 5);
} catch (e) {
  throw e; // 'Rating failed: <html>Proxy Error...' — opaque
}

// after
try {
  await rateItem(pluginId, 5);
} catch (e) {
  const msg = e instanceof Error ? e.message : String(e);
  if (msg.startsWith('Rating failed: ') && /5\d{2}|quota/i.test(msg)) {
    await backoffRetry(() => rateItem(pluginId, 5), { tries: 3 });
  } else {
    throw e;
  }
}
Defensive patterns

Strategy: try-catch

Try / catch

try {
  return await rateItem(itemId, rating);
} catch (e) {
  const msg = e instanceof Error ? e.message : String(e);
  if (!msg.startsWith('Rating failed: ')) throw e; // client-side validation → fix input
  const serverText = msg.slice('Rating failed: '.length);
  if (/^5\d{2}|quota|rate/i.test(serverText)) {
    return backoffRetry(() => rateItem(itemId, rating), { tries: 3, baseMs: 500 });
  }
  throw new Error(`Registry rejected rating: ${serverText}`, { cause: e });
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18). Data as JSON: /api/errors/2372ffa6ddfa6960. Report an issue: GitHub.