{"record":{"id":"8ecbf149e596a71f","repo":"tinyhumansai/openhuman","slug":"invalid-paramname-string-value-must-be-a","errorCode":null,"errorMessage":"Invalid ${paramName}: ${String(value)}. Must be a positive integer.","messagePattern":"Invalid (.+?): (.+?)\\. Must be a positive integer\\.","errorType":"validation","errorClass":"ValidationError","httpStatus":null,"severity":"error","filePath":"app/src/lib/mcp/validation.ts","lineNumber":91,"sourceCode":" * Validate a positive integer parameter (e.g. message IDs)\n */\nexport function validatePositiveInt(value: unknown, paramName: string): number {\n  if (typeof value === 'number') {\n    if (!Number.isInteger(value) || value <= 0) {\n      throw new ValidationError(`Invalid ${paramName}: ${value}. Must be a positive integer.`);\n    }\n    return value;\n  }\n\n  if (typeof value === 'string') {\n    const intValue = Number.parseInt(value, 10);\n    if (Number.isNaN(intValue) || intValue <= 0) {\n      throw new ValidationError(`Invalid ${paramName}: '${value}'. Must be a positive integer.`);\n    }\n    return intValue;\n  }\n\n  throw new ValidationError(`Invalid ${paramName}: ${String(value)}. Must be a positive integer.`);\n}\n\n/**\n * Validate optional ID (can be undefined)\n */\nexport function validateOptionalId(value: unknown, paramName: string): number | string | undefined {\n  if (value === undefined || value === null) {\n    return undefined;\n  }\n  return validateId(value, paramName);\n}\n","sourceCodeStart":73,"sourceCodeEnd":103,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/749120085864ce16e0f273c7b86fac7740b39c5b/app/src/lib/mcp/validation.ts#L73-L103","documentation":"The fallback branch of validatePositiveInt(): the value is neither number nor string (boolean, null, object, array, undefined passed where not allowed), so it throws ValidationError 'Invalid <param>: <String(value)>. Must be a positive integer.' — a wrong-type failure rather than a bad-value one.","triggerScenarios":"Passing null, true/false, an object ({id: 3} instead of 3), or an array ([3]) as the parameter. Typical when callers forward unvalidated JSON payloads or destructure with the wrong key.","commonSituations":"Tool params deserialized from untyped JSON where a field is sometimes an object; boolean flags accidentally passed in the ID slot due to argument-order mistakes; nulls from optional chaining defaults (value ?? null).","solutions":["Check the value's type before the call: require typeof number (integer > 0) or numeric string.","Fix argument construction — the message shows the actual value, making key-mixups visible.","Add shared param types (TS interfaces) for tool payloads so the compiler catches swapped/missing fields.","Convert booleans/objects upstream instead of relying on the validator's error at runtime."],"exampleFix":"// before\nawait tool({ message_id: payload.id ?? null });\n\n// after\nconst id = payload.id;\nif (typeof id !== 'number' || !Number.isInteger(id) || id < 1) {\n  throw new TypeError('payload.id must be a positive integer');\n}\nawait tool({ message_id: id });","handlingStrategy":"type-guard","validationCode":"function asPositiveInt(v: unknown): number | undefined {\n  if (typeof v === 'number' && Number.isInteger(v) && v > 0) return v;\n  const m = typeof v === 'string' ? /^\\d+$/.exec(v) : null;\n  return m && Number(m[0]) > 0 ? Number(m[0]) : undefined;\n}\nif (asPositiveInt(payload.id) === undefined) throw new TypeError('id must be a positive integer');","typeGuard":"function isPositiveIntLike(v: unknown): v is number | string {\n  if (typeof v === 'number') return Number.isInteger(v) && v > 0;\n  if (typeof v === 'string') return /^\\d+$/.test(v) && Number(v) > 0;\n  return false;\n}","tryCatchPattern":"try {\n  validatePositiveInt(value, paramName);\n} catch (err) {\n  if (err instanceof ValidationError) {\n    // wrong type (null/bool/object) — fix the caller's payload construction\n    logPayloadShape(value);\n    return badRequest(err.message);\n  }\n  throw err;\n}","preventionTips":["Type tool params with shared interfaces; never forward untyped JSON straight into MCP calls.","Destructure explicitly rather than passing whole objects into ID fields.","Let TypeScript strict null checks surface null/undefined before runtime."],"tags":["mcp","validation","type-error","parameters","input"],"backgroundTag":"invalid-parameter-type","analyzedSha":"749120085864ce16e0f273c7b86fac7740b39c5b","analyzedAt":"2026-08-17T21:21:45.363Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}