{"record":{"id":"4c87e5ec71be5161","repo":"phacility/phabricator","slug":"minimum-page-size-for-api-searches-is-1-but-this","errorCode":null,"errorMessage":"Minimum page size for API searches is 1, but this call specified %s.","messagePattern":"Minimum page size for API searches is 1, but this call specified (.+?)\\.","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/applications/search/engine/PhabricatorApplicationSearchEngine.php","lineNumber":1389,"sourceCode":"\n    if ($limit === null) {\n      if ($pager->getPageSize() >= 0xFFFF) {\n        return;\n      } else {\n        $limit = 100;\n      }\n    }\n\n    if ($limit > 100) {\n      throw new Exception(\n        pht(\n          'Maximum page size for Conduit API method calls is 100, but '.\n          'this call specified %s.',\n          $limit));\n    }\n\n    if ($limit < 1) {\n      throw new Exception(\n        pht(\n          'Minimum page size for API searches is 1, but this call '.\n          'specified %s.',\n          $limit));\n    }\n\n    $pager->setPageSize($limit);\n  }\n\n  private function setPagerOffsetsForConduit(\n    $pager,\n    ConduitAPIRequest $request) {\n    $before_id = $request->getValue('before');\n    if ($before_id !== null) {\n      $pager->setBeforeID($before_id);\n    }\n\n    $after_id = $request->getValue('after');","sourceCodeStart":1371,"sourceCodeEnd":1407,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/applications/search/engine/PhabricatorApplicationSearchEngine.php#L1371-L1407","documentation":"The lower-bound twin of the page-size check in setPagerSizeForConduit(): a Conduit search 'limit' below 1 (0 or negative) is rejected because a page must yield at least one result. Note the asymmetry - limit === null means 'use default', but an explicit out-of-range number is an error, not silently corrected.","triggerScenarios":"Calling `<app>.search` with `\"limit\": 0` (often a script default meaning 'no limit' or 'count only') or a negative value from arithmetic (e.g. $limit = $total - $fetched going negative on the final page).","commonSituations":"Scripts using 0 as a sentinel for unlimited (common convention elsewhere, invalid here); countdown loops computing the last page size as remainder - 1; configuration values defaulting to 0/null conflated and passed through as 0.","solutions":["Use limit between 1 and 100; omit 'limit' entirely when the default is fine.","Replace 0-unlimited sentinels: map 0/absent to null before the call, or just always request a fixed page size and rely on cursors.","Fix countdown pagination: stop the loop when the computed next-page size < 1 instead of issuing the request.","If you only need a count, look for a count-capable result mode instead of an empty page."],"exampleFix":"// before: 0 used as 'default' sentinel\n$params['limit'] = $user_limit ?: 0;\n\n// after: omit the key to get the default\nif ($user_limit) { $params['limit'] = min(100, max(1, $user_limit)); }","handlingStrategy":"validation","validationCode":"if (isset($params['limit'])) { $params['limit'] = max(1, min(100, (int)$params['limit'])); }","typeGuard":"function isPageableLimit($n) { return $n === null || (is_int($n) && $n >= 1 && $n <= 100); }","tryCatchPattern":"try {\n  $r = $client->call('maniphest.search', $params);\n} catch (Exception $ex) {\n  if (strpos($ex->getMessage(), 'Minimum page size') !== false) {\n    unset($params['limit']);\n    $r = $client->call('maniphest.search', $params);\n  }\n}","preventionTips":["Use null/omission for defaults, never 0, in Conduit params","Bound computed page sizes: max(1, $remaining)","Unit-test pagination helpers with tiny final pages"],"tags":["phabricator","conduit","search","pagination","validation"],"backgroundTag":"pagination-limit-invalid","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}