phacility/phabricator · error · PhutilProxyException
Expected JSON response from Duo.
Error message
Expected JSON response from Duo.
What it means
PhabricatorDuoFuture::didReceiveResult() decodes every Duo API response body with phutil_json_decode(); if the body is not valid JSON, the PhutilJSONParserException is wrapped in PhutilProxyException with this message. A non-JSON body means the HTTPS request reached something that is not the Duo JSON API: an HTML error/proxy page or a truncated response.
Source
Thrown at src/applications/auth/future/PhabricatorDuoFuture.php:146
}
$this->future = $future;
}
return $this->future;
}
protected function didReceiveResult($result) {
list($status, $body, $headers) = $result;
if ($status->isError()) {
throw $status;
}
try {
$data = phutil_json_decode($body);
} catch (PhutilJSONParserException $ex) {
throw new PhutilProxyException(
pht('Expected JSON response from Duo.'),
$ex);
}
return $data;
}
}
View on GitHub (pinned to 5720a38cfe)
Solutions
- From the web host run: curl -sS https://api-XXXX.duosecurity.com/ping — the body must be JSON; if not, the network path is at fault.
- Verify the provider API hostname matches the Duo integration exactly.
- Exempt *.duosecurity.com from TLS-inspection/filtering proxies.
- If Duo is having an outage, retry once service is restored.
- Confirm the integration/secret keys are valid, since some auth failures return non-JSON error pages.
Defensive patterns
Strategy: try-catch
Validate before calling
// Preflight from the web host before relying on Duo:
// curl -fsS https://api-xxxx.duosecurity.com/ping -> must print JSON
$ping = id(new PhabricatorDuoFuture())
->setIntegrationKey($ikey)
->setSecretKey($skey)
->setAPIHostname($hostname)
->setMethod('ping')
->resolve(); // throws early and clearly if the path returns non-JSON Try / catch
try {
$result = $future->resolve();
} catch (PhutilProxyException $ex) {
if ($ex->getPrevious() instanceof PhutilJSONParserException) {
// the body was not JSON: routing/proxy/outage problem,
// log raw context and report 'Duo API unreachable', then retry later
}
throw $ex;
} Prevention
- Keep *.duosecurity.com out of TLS-inspection and filtering proxies.
- Health-check /ping (expect JSON) before enrollment or debug sessions.
- Treat any non-JSON Duo response as a routing/config fault, not a Duo logic result.
- Verify integration/secret keys so auth failures do not surface as HTML error pages.
When it happens
Trigger: Resolving any PhabricatorDuoFuture ('enroll', 'enroll_status', 'preauth', 'ping') where the body is HTML or garbage: TLS interception proxy or captive portal returning HTML, wrong hostname resolving to a gateway page, Duo serving an HTML 5xx page during an outage, or a response truncated mid-transfer.
Common situations: Corporate networks with TLS inspection on *.duosecurity.com; DNS misdirection or hostname typo; transient Duo incidents; web host behind a filtering egress proxy.
Related errors
- Configuration file is not properly formatted JSON. %s
- This Duo enrollment attempt is invalid or has expired ("%s")
- Unable to load Duo API credential ("%s").
- Duo API credential ("%s") has no secret key.
- Duo username pairing mode ("%s") is not supported.
AI-assisted analysis of phacility/phabricator@5720a38cfe (2026-08-21).
Data as JSON: /api/errors/2ad57542bde63558.
Report an issue: GitHub.