{"record":{"id":"2337e40040852f32","repo":"phacility/phabricator","slug":"err-rate-limit","errorCode":"ERR-RATE-LIMIT","errorMessage":"ERR-RATE-LIMIT","messagePattern":"ERR-RATE-LIMIT","errorType":"error_code","errorClass":"ConduitException","httpStatus":null,"severity":"error","filePath":"src/applications/conduit/method/ConduitGetCertificateConduitAPIMethod.php","lineNumber":49,"sourceCode":"  }\n\n  protected function defineErrorTypes() {\n    return array(\n      'ERR-BAD-TOKEN' => pht('Token does not exist or has expired.'),\n      'ERR-RATE-LIMIT' => pht(\n        'You have made too many invalid token requests recently. Wait before '.\n        'making more.'),\n    );\n  }\n\n  protected function execute(ConduitAPIRequest $request) {\n    $failed_attempts = PhabricatorUserLog::loadRecentEventsFromThisIP(\n      PhabricatorConduitCertificateFailureUserLogType::LOGTYPE,\n      60 * 5);\n\n    if (count($failed_attempts) > 5) {\n      $this->logFailure($request);\n      throw new ConduitException('ERR-RATE-LIMIT');\n    }\n\n    $token = $request->getValue('token');\n    $info = id(new PhabricatorConduitCertificateToken())->loadOneWhere(\n      'token = %s',\n      trim($token));\n\n    if (!$info || $info->getDateCreated() < time() - (60 * 15)) {\n      $this->logFailure($request, $info);\n      throw new ConduitException('ERR-BAD-TOKEN');\n    } else {\n      $log = PhabricatorUserLog::initializeNewLog(\n          $request->getUser(),\n          $info->getUserPHID(),\n          PhabricatorConduitCertificateUserLogType::LOGTYPE)\n        ->save();\n    }\n","sourceCodeStart":31,"sourceCodeEnd":67,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/applications/conduit/method/ConduitGetCertificateConduitAPIMethod.php#L31-L67","documentation":"conduit.getcertificate counts certificate-failure events logged from the current IP over the last 5 minutes (PhabricatorUserLog::loadRecentEventsFromThisIP). More than 5 failures trips 'ERR-RATE-LIMIT', and the rejected attempt is itself logged as another failure, extending the pressure on the IP.","triggerScenarios":"A retry loop hammering conduit.getcertificate with bad tokens; several developers or CI runners behind one NAT IP accumulating failures; automated scripts retrying immediately on every auth error.","commonSituations":"A misconfigured integration stuck in a hot retry loop blocking the whole office NAT; shared build-farm egress addresses where one broken job locks out all others.","solutions":["Stop all attempts from that IP for at least 5 minutes so the failure events age out of the window.","Find and fix the underlying bad-token/credential source (see ERR-BAD-TOKEN) before resuming, otherwise the limit immediately re-trips.","Add exponential backoff to retry logic and identify the offending client via the Phabricator activity/people log."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  $result = $call->execute();\n} catch (ConduitException $ex) {\n  if ($ex->getMessage() === 'ERR-RATE-LIMIT') {\n    // Sleep > 5 minutes, fix the underlying bad token, then retry once.\n  }\n}","preventionTips":["Cap retries on certificate fetches (e.g. 3 attempts with exponential backoff), never tight loops.","Remember the window is per IP: coordinate CI runners sharing NAT egress.","Investigate the first ERR-BAD-TOKEN instead of retrying through the rate limit."],"tags":["conduit","rate-limit","auth","phabricator","php"],"backgroundTag":"api-rate-limit-exceeded","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}