{"record":{"id":"70ac96c2761d7171","repo":"can1357/oh-my-pi","slug":"sqlite-limit-must-be-a-positive-integer-got-va","errorCode":null,"errorMessage":"SQLite limit must be a positive integer; got '${value}'","messagePattern":"SQLite limit must be a positive integer; got '(.+?)'","errorType":"validation","errorClass":"ToolError","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/tools/sqlite-reader.ts","lineNumber":300,"sourceCode":"\n\tfor (const row of rows) {\n\t\tconst cells = columns.map((column, index) =>\n\t\t\tpadCell(stringifySqliteValue(row[column]), widths[index] ?? MIN_COLUMN_WIDTH),\n\t\t);\n\t\tlines.push(`| ${cells.join(\" | \")} |`);\n\t}\n\n\treturn lines.map(line => truncateToWidth(replaceTabs(line), MAX_RENDER_WIDTH)).join(\"\\n\");\n}\n\nfunction parseLimit(value: string | null, fallback: number): number {\n\tif (value === null || value.trim().length === 0) {\n\t\treturn fallback;\n\t}\n\n\tconst parsed = Number.parseInt(value, 10);\n\tif (!Number.isFinite(parsed) || parsed < 1) {\n\t\tthrow new ToolError(`SQLite limit must be a positive integer; got '${value}'`);\n\t}\n\treturn Math.min(parsed, MAX_QUERY_LIMIT);\n}\n\nfunction parseOffset(value: string | null): number {\n\tif (value === null || value.trim().length === 0) {\n\t\treturn 0;\n\t}\n\n\tconst parsed = Number.parseInt(value, 10);\n\tif (!Number.isFinite(parsed) || parsed < 0) {\n\t\tthrow new ToolError(`SQLite offset must be a non-negative integer; got '${value}'`);\n\t}\n\treturn parsed;\n}\n\nfunction getTableMasterRow(db: Database, table: string): SqliteMasterRow {\n\tconst row =","sourceCodeStart":282,"sourceCodeEnd":318,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/tools/sqlite-reader.ts#L282-L318","documentation":"parseLimit validates the `limit` query parameter of SQLite selector URLs (e.g. db.sqlite?table=t&limit=10). It throws this ToolError when limit is present, non-empty, and not a parseable integer >= 1 (e.g. 'abc', '0', '-5', '1.5'). Values parse via Number.parseInt base 10, and valid values are clamped to MAX_QUERY_LIMIT (500).","triggerScenarios":"A sqlite-reader selector with limit=0, a negative limit, a float, a non-numeric string, or a value with stray characters like '10px'; empty string is allowed and falls back.","commonSituations":"Programmatic URL building that stringifies 0 or NaN; copying limits with units from other tools; off-by-one assumptions that limit starts at 0; UI inputs passed through unvalidated.","solutions":["Pass a positive integer (1..500) as limit, or omit it to use the default (20).","Sanitize the value before building the selector: Number.parseInt and check Number.isInteger(n) && n >= 1.","Clamp large values yourself or rely on the built-in clamp to 500 — no need to cap manually."],"exampleFix":"// before\nconst url = `data.sqlite?table=users&limit=${limit ?? 0}`;\n// after\nconst n = Math.max(1, Math.floor(Number(limit) || 20));\nconst url = `data.sqlite?table=users&limit=${n}`;","handlingStrategy":"validation","validationCode":"function safeLimit(v: string | null | undefined): string | undefined {\n  if (v == null || v.trim() === \"\") return undefined;\n  const n = Number.parseInt(v, 10);\n  if (!Number.isInteger(n) || n < 1) throw new Error(`bad limit: ${v}`);\n  return String(Math.min(n, 500));\n}","typeGuard":"function isPositiveIntString(v: string): boolean { return /^\\d+$/.test(v.trim()) && Number.parseInt(v, 10) >= 1; }","tryCatchPattern":"try { return await readSelector(url); } catch (e) { if (e instanceof ToolError && e.message.startsWith(\"SQLite limit must be\")) { return readSelector(setQueryParam(url, \"limit\", \"20\")); } throw e; }","preventionTips":["Only interpolate sanitized integers into selector query strings.","Remember limit starts at 1, not 0.","Rely on the built-in clamp of 500 instead of passing oversized values."],"tags":["validation","parameters","sqlite"],"backgroundTag":"invalid-parameter-value","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}