{"record":{"id":"1923adf4cd4ea613","repo":"github/github-mcp-server","slug":"non-integer-numeric-value-v","errorCode":null,"errorMessage":"non-integer numeric value: %v","messagePattern":"non-integer numeric value: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/github/params.go","lineNumber":84,"sourceCode":"func toInt(val any) (int, error) {\n\tvar f float64\n\tswitch v := val.(type) {\n\tcase float64:\n\t\tf = v\n\tcase string:\n\t\tvar err error\n\t\tf, err = strconv.ParseFloat(v, 64)\n\t\tif err != nil {\n\t\t\treturn 0, fmt.Errorf(\"invalid numeric value: %s\", v)\n\t\t}\n\tdefault:\n\t\treturn 0, fmt.Errorf(\"expected number, got %T\", val)\n\t}\n\tif math.IsNaN(f) || math.IsInf(f, 0) {\n\t\treturn 0, fmt.Errorf(\"non-finite numeric value\")\n\t}\n\tif f != math.Trunc(f) {\n\t\treturn 0, fmt.Errorf(\"non-integer numeric value: %v\", f)\n\t}\n\tif f > math.MaxInt || f < math.MinInt {\n\t\treturn 0, fmt.Errorf(\"numeric value out of int range: %v\", f)\n\t}\n\treturn int(f), nil\n}\n\n// toInt64 converts a value to int64, handling both float64 and string representations.\n// Some MCP clients send numeric values as strings. It rejects NaN, ±Inf,\n// fractional values, and values that lose precision in the float64→int64 conversion.\nfunc toInt64(val any) (int64, error) {\n\tvar f float64\n\tswitch v := val.(type) {\n\tcase float64:\n\t\tf = v\n\tcase string:\n\t\tvar err error\n\t\tf, err = strconv.ParseFloat(v, 64)","sourceCodeStart":66,"sourceCodeEnd":102,"githubUrl":"https://github.com/github/github-mcp-server/blob/0ea1f775a7c73eff1bd2e25904d01136756bbfe2/pkg/github/params.go#L66-L102","documentation":"Thrown by toInt in pkg/github/params.go when a numeric value has a fractional part (f != math.Trunc(f)). Int-typed tool parameters (page, per_page, issue_number, etc.) must be whole numbers even when sent as strings or JSON floats.","triggerScenarios":"per_page: 30.5, page: 1.2, or per_page: \"29.99\" passed to an int parameter; averaged/computed pagination values forwarded without rounding.","commonSituations":"Client arithmetic producing floats (e.g. total/limit); spreadsheets or config files storing 30.0-style decimals; LLMs emitting decimal values for count fields.","solutions":["Round or floor the value client-side and send a whole number.","Check for stray decimals in string-form numbers, including thousands separators like \"1.000\" (parsed as 1.0, which is integral, but \"1.5\" fails).","Use Math.round/Math.floor deliberately, not implicit string coercion."],"exampleFix":"// before\nconst perPage = totalItems / maxPages; // e.g. 27.5\narguments = { owner, repo, per_page: perPage };\n// after\nconst perPage = Math.ceil(totalItems / maxPages);\narguments = { owner, repo, per_page: perPage };","handlingStrategy":"validation","validationCode":"function intArg(name, v) {\n  const n = typeof v === \"string\" ? Number(v) : v;\n  if (typeof n !== \"number\" || !Number.isFinite(n) || !Number.isInteger(n)) {\n    throw new Error(`${name} must be an integer, got ${JSON.stringify(v)}`);\n  }\n  return n;\n}","typeGuard":"function isIntegerLike(v: unknown): v is number {\n  const n = typeof v === \"string\" ? Number(v) : v;\n  return typeof n === \"number\" && Number.isInteger(n);\n}","tryCatchPattern":"On 'non-integer numeric value: <v>', apply Math.round or Math.floor deliberately, then retry; do not blind-cast.","preventionTips":["Round all computed pagination/count values before building arguments.","Watch locale-formatted strings (commas/dots) in numeric fields.","Unit-test client helpers that compute per_page/page with odd totals."],"tags":["validation","numeric","fractional","argument-parsing","mcp-tool"],"backgroundTag":null,"analyzedSha":"0ea1f775a7c73eff1bd2e25904d01136756bbfe2","analyzedAt":"2026-08-15T18:10:19.804Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}