{"record":{"id":"24a42665d015dc04","repo":"rohitg00/agentmemory","slug":"mem-search-limit-must-be-a-positive-integer","errorCode":null,"errorMessage":"mem::search: limit must be a positive integer","messagePattern":"mem::search: limit must be a positive integer","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/functions/search.ts","lineNumber":391,"sourceCode":"      limit?: number\n      project?: string\n      cwd?: string\n      format?: string\n      token_budget?: number\n      agentId?: string\n    }) => {\n      const idx = getSearchIndex()\n\n      // Input validation / normalization.\n      if (typeof data?.query !== 'string' || !data.query.trim()) {\n        throw new Error('mem::search: query must be a non-empty string')\n      }\n      const query = data.query.trim()\n      const MAX_LIMIT = 100\n      let effectiveLimit = 20\n      if (data.limit !== undefined) {\n        if (!Number.isInteger(data.limit) || data.limit < 1) {\n          throw new Error('mem::search: limit must be a positive integer')\n        }\n        effectiveLimit = Math.min(data.limit, MAX_LIMIT)\n      }\n      const projectFilter = typeof data.project === 'string' && data.project.trim().length > 0 ? data.project.trim() : undefined\n      const cwdFilter = typeof data.cwd === 'string' && data.cwd.trim().length > 0 ? data.cwd.trim() : undefined\n      // #817: agent-scope isolation. mem::search backs REST /search,\n      // memory_recall and recall_context. Without filtering here a\n      // worker booted with AGENT_ID=B + AGENTMEMORY_AGENT_SCOPE=isolated\n      // could read A's memories — the cross-agent leak the issue\n      // documented. Mirrors the smart-search pattern: wildcard \"*\"\n      // bypasses, explicit agentId pins, isolated mode falls back to\n      // the worker's own AGENT_ID.\n      //\n      // Fail-closed: if isolated mode is on AND no explicit agentId\n      // is given AND env AGENT_ID is unset, refuse the call rather\n      // than silently dropping the filter. Allowing the call through\n      // with filterAgentId=undefined is the same leak this fix is\n      // supposed to close.","sourceCodeStart":373,"sourceCodeEnd":409,"githubUrl":"https://github.com/rohitg00/agentmemory/blob/e04ba88819c365c9acf9d6661ea802143e728bd6/src/functions/search.ts#L373-L409","documentation":"mem::search accepts an optional limit that must be a positive integer (default 20, capped at MAX_LIMIT 100). Non-integers, zero, negative numbers, and non-numeric values are rejected with this error before any search runs.","triggerScenarios":"Calling mem::search with limit: 0, limit: -5, limit: 10.5, limit: '20' (string), or NaN — any value that is defined but fails Number.isInteger(v) && v >= 1.","commonSituations":"Passing a page size of 0 to mean 'no limit'; forwarding a string from a query-string parameter without Number() coercion; floating-point results from a size calculation.","solutions":["Omit limit entirely to use the default of 20.","Coerce and validate: pass Math.floor(Number(v)) only when it is a positive integer.","Remember values above 100 are clamped (not rejected) — only non-positive-integers throw.","Fix query-string parsing to convert numeric strings to numbers."],"exampleFix":"// before\nconst limit = Number(searchParams.get('limit')); // NaN or 0 possible\nawait trigger({ function_id: 'mem::search', payload: { query: q, limit } });\n// after\nconst raw = Number(searchParams.get('limit'));\nconst limit = Number.isInteger(raw) && raw >= 1 ? raw : undefined;\nawait trigger({ function_id: 'mem::search', payload: { query: q, limit } });","handlingStrategy":"validation","validationCode":"function toLimit(v: unknown): number | undefined {\n  if (v === undefined || v === null) return undefined;\n  const n = Number(v);\n  return Number.isInteger(n) && n >= 1 ? n : undefined;\n}","typeGuard":"function isPositiveInt(v: unknown): v is number {\n  return typeof v === 'number' && Number.isInteger(v) && v >= 1;\n}","tryCatchPattern":"try {\n  return await trigger({ function_id: 'mem::search', payload: { query, limit } });\n} catch (e) {\n  if (String(e.message).includes('limit must be a positive integer')) {\n    return await trigger({ function_id: 'mem::search', payload: { query } });\n  }\n  throw e;\n}","preventionTips":["Coerce query-string params with Number() before use.","Map 0/'unlimited' to undefined rather than 0.","Clamp page-size math with Math.floor/Math.min.","Add validation at the REST handler boundary."],"tags":["validation","search","pagination"],"backgroundTag":"invalid-pagination-parameter","analyzedSha":"e04ba88819c365c9acf9d6661ea802143e728bd6","analyzedAt":"2026-08-30T01:07:40.754Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}