roundcube/roundcubemail · error · Exception
Failed to fetch data, HTTP status
Error message
Failed to fetch data, HTTP status {$code} What it means
The Stalwart password driver's fetch_user() issues an HTTP GET to the Stalwart admin API and only accepts HTTP 200. Any other status code (401/403 auth failure, 404 wrong endpoint, 5xx server error) causes this generic exception, which propagates out of save() when a user tries to change their password.
Solutions
- Verify plugins/password config for the stalwart driver: correct host, port, API path, and admin credentials (test with curl against the same URL).
- Check the HTTP status code in the Roundcube error log / PHP log to identify 401 (auth) vs 404 (path) vs 5xx (server).
- Confirm TLS certificates are valid; if using self-signed certs configure the HTTP client options accordingly.
- Check Stalwart server logs for the corresponding request and error detail.
Example fix
// before
throw new \Exception("Failed to fetch data, HTTP status {$code}");
// after
throw new \Exception("Failed to fetch user from Stalwart, HTTP status {$code}, url: {$url}"); Defensive patterns
Strategy: try-catch
Validate before calling
// before changing password, probe the Stalwart API
$ch = curl_init($apiUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$httpCode = curl_getinfo(curl_exec($ch) ? $ch : $ch, CURLINFO_RESPONSE_CODE);
if ($httpCode !== 200) { /* abort and show admin error */ } Try / catch
try { $driver->save($curpass, $newpass, $username); } catch (\Exception $e) { rcube::raise_error(['message' => 'Password change failed: ' . $e->getMessage()], true, false); return false; } Prevention
- Smoke-test the Stalwart admin endpoint with curl after every config or upgrade change.
- Keep admin credentials in a monitored secret and alert on expiry.
- Log the HTTP status code alongside the exception for faster diagnosis.
- Add a monitoring check for the Stalwart API availability.
When it happens
Trigger: save() -> fetch_user() with a Stalwart host returning non-200: wrong API URL/path, expired or wrong admin credentials in the driver config, Stalwart unreachable via TLS mismatch, or Stalwart returning 5xx during the lookup of the user record.
Common situations: Roundcube password plugin configured with wrong stalwart_host/api path or stale admin token; Stalwart upgraded and endpoint moved; reverse proxy returning 404/502; DNS/firewall issues in production.
Understand the failure class
Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.
Related errors
AI-assisted analysis of roundcube/roundcubemail@4b54c2acfb (2026-09-14).
Data as JSON: /api/errors/c8912bf3ffdd3e01.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/password/drivers/stalwart.php:59
private function fetch_user($username)
{
$config = rcmail::get_instance()->config;
$url = $config->get('password_stalwart_api_host');
$token = $config->get('password_stalwart_api_token');
$client = password::get_http_client();
$response = $client->request('GET', $url . '/principal/' . $username, [
'headers' => [
'Authorization' => 'Bearer ' . $token,
'Accept' => 'application/json',
],
]);
$code = $response->getStatusCode();
$resp = (string) $response->getBody();
if ($code !== 200) {
throw new \Exception("Failed to fetch data, HTTP status {$code}");
}
return json_decode($resp, true);
}
public function save($curpass, $newpass, $username)
{
$client = password::get_http_client();
$config = rcmail::get_instance()->config;
$url = $config->get('password_stalwart_api_host');
$token = $config->get('password_stalwart_api_token');
try {
$data = $this->fetch_user($username);
if (!isset($data['data']['secrets'])) {
return PASSWORD_ERROR;
}View on GitHub (pinned to 4b54c2acfb)