phacility/phabricator · error · ConduitException
ERR-BAD-TOKEN
ERR-BAD-TOKEN
Error message
ERR-BAD-TOKEN
What it means
conduit.getcertificate looks up the trimmed 'token' value in phabricator_conduit_certificate_token and requires the row to be no older than 15 minutes. A missing row (unknown token) or an expired one (>900s old) both yield 'ERR-BAD-TOKEN', and the failure is logged against the requesting IP.
Source
Thrown at src/applications/conduit/method/ConduitGetCertificateConduitAPIMethod.php:59
protected function execute(ConduitAPIRequest $request) {
$failed_attempts = PhabricatorUserLog::loadRecentEventsFromThisIP(
PhabricatorConduitCertificateFailureUserLogType::LOGTYPE,
60 * 5);
if (count($failed_attempts) > 5) {
$this->logFailure($request);
throw new ConduitException('ERR-RATE-LIMIT');
}
$token = $request->getValue('token');
$info = id(new PhabricatorConduitCertificateToken())->loadOneWhere(
'token = %s',
trim($token));
if (!$info || $info->getDateCreated() < time() - (60 * 15)) {
$this->logFailure($request, $info);
throw new ConduitException('ERR-BAD-TOKEN');
} else {
$log = PhabricatorUserLog::initializeNewLog(
$request->getUser(),
$info->getUserPHID(),
PhabricatorConduitCertificateUserLogType::LOGTYPE)
->save();
}
$user = id(new PhabricatorUser())->loadOneWhere(
'phid = %s',
$info->getUserPHID());
if (!$user) {
throw new Exception(pht('Certificate token points to an invalid user!'));
}
return array(
'username' => $user->getUserName(),
'certificate' => $user->getConduitCertificate(),View on GitHub (pinned to 5720a38cfe)
Solutions
- Generate a new token and call conduit.getcertificate with it immediately, within the 15-minute validity window.
- Verify the token is transmitted intact (no trailing newline/whitespace; it is trimmed server-side but must otherwise match exactly).
- If failures repeat, stop quickly: five failures per IP per 5 minutes trigger ERR-RATE-LIMIT.
Defensive patterns
Strategy: retry
Try / catch
try {
$result = $call->execute();
} catch (ConduitException $ex) {
if ($ex->getMessage() === 'ERR-BAD-TOKEN') {
// Mint a NEW token and retry immediately once; old tokens cannot be revived.
}
} Prevention
- Generate the token immediately before redeeming it; the lifetime is only 15 minutes.
- Never persist or reuse tokens across runs.
- Abort after a couple of failures to avoid tripping ERR-RATE-LIMIT (5 failures / 5 min / IP).
When it happens
Trigger: Delaying more than 15 minutes between generating the token and redeeming it; reusing a token from a previous session; a token truncated or altered by shell quoting/whitespace.
Common situations: Debugging a client step-by-step so the token expires in between; caching tokens in scripts or docs instead of minting them fresh per run.
Related errors
- ERR-INVALID-USER
- ERR-INVALID-CERTIFICATE
- ERR-NO-CERTIFICATE
- ERR-RATE-LIMIT
- Certificate token points to an invalid user!
AI-assisted analysis of phacility/phabricator@5720a38cfe (2026-08-21).
Data as JSON: /api/errors/3ff6d2c55773f518.
Report an issue: GitHub.