{"record":{"id":"c8912bf3ffdd3e01","repo":"roundcube/roundcubemail","slug":"failed-to-fetch-data-http-status-code","errorCode":null,"errorMessage":"Failed to fetch data, HTTP status {$code}","messagePattern":"Failed to fetch data, HTTP status (.+?)","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"plugins/password/drivers/stalwart.php","lineNumber":59,"sourceCode":"    private function fetch_user($username)\n    {\n        $config = rcmail::get_instance()->config;\n        $url = $config->get('password_stalwart_api_host');\n        $token = $config->get('password_stalwart_api_token');\n\n        $client = password::get_http_client();\n        $response = $client->request('GET', $url . '/principal/' . $username, [\n            'headers' => [\n                'Authorization' => 'Bearer ' . $token,\n                'Accept' => 'application/json',\n            ],\n        ]);\n\n        $code = $response->getStatusCode();\n        $resp = (string) $response->getBody();\n\n        if ($code !== 200) {\n            throw new \\Exception(\"Failed to fetch data, HTTP status {$code}\");\n        }\n\n        return json_decode($resp, true);\n    }\n\n    public function save($curpass, $newpass, $username)\n    {\n        $client = password::get_http_client();\n        $config = rcmail::get_instance()->config;\n        $url = $config->get('password_stalwart_api_host');\n        $token = $config->get('password_stalwart_api_token');\n\n        try {\n            $data = $this->fetch_user($username);\n\n            if (!isset($data['data']['secrets'])) {\n                return PASSWORD_ERROR;\n            }","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/roundcube/roundcubemail/blob/4b54c2acfb54d5ee3d1c281ca7f143bed0dea804/plugins/password/drivers/stalwart.php#L41-L77","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nthrow new \\Exception(\"Failed to fetch data, HTTP status {$code}\");\n// after\nthrow new \\Exception(\"Failed to fetch user from Stalwart, HTTP status {$code}, url: {$url}\");","handlingStrategy":"try-catch","validationCode":"// before changing password, probe the Stalwart API\n$ch = curl_init($apiUrl);\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n$httpCode = curl_getinfo(curl_exec($ch) ? $ch : $ch, CURLINFO_RESPONSE_CODE);\nif ($httpCode !== 200) { /* abort and show admin error */ }","typeGuard":null,"tryCatchPattern":"try { $driver->save($curpass, $newpass, $username); } catch (\\Exception $e) { rcube::raise_error(['message' => 'Password change failed: ' . $e->getMessage()], true, false); return false; }","preventionTips":["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."],"tags":["network","http","password-driver","stalwart"],"backgroundTag":"http-error-response","analyzedSha":"4b54c2acfb54d5ee3d1c281ca7f143bed0dea804","analyzedAt":"2026-09-14T13:23:19.231Z","contentChangedAt":"2026-09-14T13:23:19.231Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}