{"record":{"id":"2cb9c5171dcb2a38","repo":"github/github-mcp-server","slug":"perpage-value-d-cannot-be-negative","errorCode":null,"errorMessage":"perPage value %d cannot be negative","messagePattern":"perPage value (.+?) cannot be negative","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/github/params.go","lineNumber":480,"sourceCode":"\tPrevCursor      string `json:\"prevCursor,omitempty\"`\n}\n\nfunc buildPageInfo(resp *github.Response) pageInfo {\n\treturn pageInfo{\n\t\tHasNextPage:     resp.After != \"\",\n\t\tHasPreviousPage: resp.Before != \"\",\n\t\tNextCursor:      resp.After,\n\t\tPrevCursor:      resp.Before,\n\t}\n}\n\n// ToGraphQLParams converts cursor pagination parameters to GraphQL-specific parameters.\nfunc (p CursorPaginationParams) ToGraphQLParams() (*GraphQLPaginationParams, error) {\n\tif p.PerPage > 100 {\n\t\treturn nil, fmt.Errorf(\"perPage value %d exceeds maximum of 100\", p.PerPage)\n\t}\n\tif p.PerPage < 0 {\n\t\treturn nil, fmt.Errorf(\"perPage value %d cannot be negative\", p.PerPage)\n\t}\n\tfirst := int32(p.PerPage)\n\n\tvar after *string\n\tif p.After != \"\" {\n\t\tafter = &p.After\n\t}\n\n\treturn &GraphQLPaginationParams{\n\t\tFirst: &first,\n\t\tAfter: after,\n\t}, nil\n}\n\ntype GraphQLPaginationParams struct {\n\tFirst *int32\n\tAfter *string\n}","sourceCodeStart":462,"sourceCodeEnd":498,"githubUrl":"https://github.com/github/github-mcp-server/blob/0ea1f775a7c73eff1bd2e25904d01136756bbfe2/pkg/github/params.go#L462-L498","documentation":"Returned by CursorPaginationParams.ToGraphQLParams when perPage is negative. first/last in GitHub's GraphQL pagination must be non-negative, so the guard rejects the request before it reaches the API. Negative values normally indicate a parsing or configuration bug upstream rather than user intent.","triggerScenarios":"Arithmetic that computes page size as page*limit - offset gone negative; config defaulting to -1 as an 'unset' sentinel being forwarded verbatim; a client computing per_page as (remaining budget) which goes negative at the end of a crawl; sign errors when negating a value.","commonSituations":"'-1 means unlimited' conventions from other SDKs leaking into this server's per_page; crawler/scraper frameworks deriving page sizes dynamically; test fixtures with negative sizes.","solutions":["Use 0 (or omit per_page) to signal 'server default' — never -1","Clamp derived page sizes: if perPage < 0 { perPage = 0 } before building the call","Audit any arithmetic that computes per_page for underflow at boundary conditions"],"exampleFix":"// before\nperPage := remainingItems - fetchedSoFar // can go negative\n// after\nperPage := remainingItems - fetchedSoFar\nif perPage < 0 {\n    perPage = 0\n}","handlingStrategy":"validation","validationCode":"func normalizePerPage(n int) int {\n    if n < 0 {\n        return 0 // 0 = server default\n    }\n    if n > 100 {\n        return 100\n    }\n    return n\n}","typeGuard":"func isNonNegative(n int) bool {\n    return n >= 0\n}","tryCatchPattern":"if _, err := p.ToGraphQLParams(); err != nil && strings.Contains(err.Error(), \"cannot be negative\") {\n    // programming bug upstream: fix the computation, don't retry\n    logAndAlert(\"negative per_page produced by pagination math\")\n}","preventionTips":["Use 0 or omission for 'default page size', never -1 sentinels","Guard derived page-size math with max(0, n) at the boundary","Unit-test pagination arithmetic at boundary conditions (remaining=0, fetched>remaining)"],"tags":["go","github-api","graphql","pagination","validation"],"backgroundTag":null,"analyzedSha":"0ea1f775a7c73eff1bd2e25904d01136756bbfe2","analyzedAt":"2026-08-15T18:10:19.804Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}