roundcube/roundcubemail · critical · RuntimeException
incorrect response from
Error message
incorrect response from %s
What it means
During OAuth discovery, rcmail_oauth::init() fetches the provider's OpenID configuration from the well-known URI and requires an 'issuer' field. If the response is not valid discovery metadata (HTML error page, wrong URL, proxy interference, non-JSON body), json_decode yields no 'issuer' and this exception is thrown.
Solutions
- curl the well-known URI and verify it returns JSON containing 'issuer'.
- Correct the oauth 'issuer' / discovery URL in Roundcube config.
- Clear the discovery cache (the $key_cache entry) so a fixed endpoint is re-fetched.
- Check for proxies/firewalls rewriting the response and ensure the request includes required auth headers if the endpoint is protected.
Example fix
// before $config_uri = 'https://idp.example.com/.well-known/openid-configuration'; // 404 HTML page // after $config_uri = 'https://idp.example.com/realms/main/.well-known/openid-configuration';
Defensive patterns
Strategy: validation
Validate before calling
$resp = file_get_contents($config_uri);
$data = json_decode($resp, true);
if (!is_array($data) || !isset($data['issuer'])) { /* abort init: bad discovery document */ } Type guard
function isValidDiscovery($data): bool { return is_array($data) && isset($data['issuer']) && is_string($data['issuer']); } Try / catch
try { $rcmail->oauth->init(); } catch (\RuntimeException $e) { rcube::raise_error(['message' => 'OIDC discovery failed: ' . $e->getMessage()], true, false); } Prevention
- curl the well-known URI after any IDP deployment or realm change.
- Bypass or correctly configure proxies for the discovery request.
- Clear the discovery cache when changing issuer config.
- Pin and monitor the discovery endpoint in health checks.
When it happens
Trigger: discover() (called from init()) GETs {issuer}/.well-known/openid-configuration and the decoded JSON has no 'issuer' key — wrong well-known URL, IDP returning an error page, or a truncated/cached bad response.
Common situations: oauth_provider option 'issuer' typo; IDP behind a proxy returning HTML error pages; provider config endpoint moved; stale cache entry from an earlier bad discovery.
Understand the failure class
Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.
Related errors
- Failed to validate JWT: invalid azp value
- Failed to validate JWT: invalid aud value
- Failed to validate JWT: missing aud/azp value
- Failed to validate JWT: issuer mismatch
- Failed to validate JWT: expired message
AI-assisted analysis of roundcube/roundcubemail@4b54c2acfb (2026-09-14).
Data as JSON: /api/errors/84ef60ece124b8bb.
Report an issue: GitHub.
Appendix: source
Thrown at program/include/rcmail_oauth.php:228
if (empty($config_uri)) {
return;
}
$key_cache = 'discovery.' . md5($config_uri);
try {
$data = $this->cache ? $this->cache->get($key_cache) : null;
if ($data === null) {
// Caveat: if .well-known URL is not answering it will break login display (will not display the button)
$response = $this->http_client->get($config_uri);
$data = json_decode($response->getBody(), true);
$this->log_debug('fetched OIDC config: %s', json_encode($data));
// sanity check
if (!isset($data['issuer'])) {
throw new \RuntimeException('incorrect response from %s', $config_uri);
}
// cache answer
if ($this->cache) {
$this->cache->set($key_cache, $data);
}
}
// map discovery to our options
foreach (self::$config_mapper as $config_key => $options_key) {
if (!empty($data[$config_key])) {
$this->options[$options_key] = $data[$config_key];
}
}
// check if pkce method is supported by this server
if ($this->options['pkce'] && isset($data['code_challenge_methods_supported']) && is_array($data['code_challenge_methods_supported'])) {
if (!in_array($this->options['pkce'], $data['code_challenge_methods_supported'])) {View on GitHub (pinned to 4b54c2acfb)