{"record":{"id":"bff5951a67f0b9db","repo":"ruvnet/ruflo","slug":"rating-must-be-integer-1-5","errorCode":null,"errorMessage":"Rating must be integer 1-5","messagePattern":"Rating must be integer 1-5","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"v3/@claude-flow/cli/src/services/registry-api.ts","lineNumber":64,"sourceCode":" */\nfunction validateRating(rating: number): boolean {\n  return Number.isInteger(rating) && rating >= 1 && rating <= 5;\n}\n\n/**\n * Rate a plugin or model\n */\nexport async function rateItem(\n  itemId: string,\n  rating: number,\n  itemType: 'plugin' | 'model' = 'plugin',\n  userId?: string\n): Promise<RatingResponse> {\n  if (!validateItemId(itemId)) {\n    throw new Error('Invalid item ID');\n  }\n  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  }","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/cli/src/services/registry-api.ts#L46-L82","documentation":"Thrown by rateItem() in the registry API client before any network call: the rating argument failed validateRating(), which requires Number.isInteger(rating) and a value in [1, 5]. This is a client-side input-validation guard protecting the Cloud Functions rating endpoint from garbage input. It fires synchronously, so no HTTP request is wasted.","triggerScenarios":"Calling rateItem(itemId, rating) with a non-integer number (4.5, NaN, Infinity), an out-of-range integer (0, 6, 10), a numeric string ('4' — fails Number.isInteger), or a value parsed from a star-widget UI that yields 0 on empty selection.","commonSituations":"Rating comes from a form/CLI flag as a string and is passed without Number() conversion; UI uses a 0–10 or 0–100 scale while the API expects 1–5; parseFloat('4.5') on a half-star widget; passing a default of 0 or -1 when the user skipped the rating.","solutions":["Convert the input with Number() (or parseInt with radix 10) before calling rateItem, then verify Number.isInteger and the 1–5 range yourself and show a friendly message.","If your UI uses a different scale (e.g. 0–10), map it to 1–5 before calling (Math.max(1, Math.min(5, Math.round(value / 2)))).","Constrain the input at the source: HTML <input type=\"number\" min=\"1\" max=\"5\" step=\"1\"> or an enum of literal 1|2|3|4|5.","Add boundary tests for 0, 1, 5, 6, '3', 3.5 so regressions in parsing surface locally instead of from the library."],"exampleFix":"// before\nconst rating = parseFloat(args['--rating']); // '4.5' or '0' → throws 'Rating must be integer 1-5'\nawait rateItem(pluginId, rating);\n\n// after\nconst rating = Number(args['--rating']);\nif (!Number.isInteger(rating) || rating < 1 || rating > 5) {\n  throw new RangeError(`Invalid rating '${args['--rating']}': must be an integer 1-5`);\n}\nawait rateItem(pluginId, rating);","handlingStrategy":"validation","validationCode":"const isValidRating = (r: unknown): r is number =>\n  typeof r === 'number' && Number.isInteger(r) && r >= 1 && r <= 5;\n\n// before calling rateItem:\nif (!isValidRating(rawRating)) {\n  throw new RangeError(`Rating must be integer 1-5, got ${JSON.stringify(rawRating)}`);\n}\nawait rateItem(itemId, rawRating, 'plugin');","typeGuard":"function isValidRating(r: unknown): r is number {\n  return typeof r === 'number' && Number.isInteger(r) && r >= 1 && r <= 5;\n}","tryCatchPattern":"try {\n  await rateItem(itemId, rating);\n} catch (e) {\n  if (e instanceof Error && e.message === 'Rating must be integer 1-5') {\n    // re-prompt the user / normalize input, then retry once\n  } else throw e;\n}","preventionTips":["Parse rating input with Number() at the boundary and reject non-integers there with a domain-specific error.","Constrain the UI: <input type=\"number\" min=\"1\" max=\"5\" step=\"1\"> or a 1–5 star control.","Type the parameter as 1|2|3|4|5 (union of literals) so invalid values fail at compile time.","Unit-test boundaries 0, 1, 5, 6, '3', 3.5, NaN against your own guard before wiring the API."],"tags":["validation","rating","registry-api","input-validation","typescript"],"backgroundTag":"input-validation-failed","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}