{"record":{"id":"7791ac54f3ea6c92","repo":"apereo/cas","slug":"reaching-duo-has-failed-with-error","errorCode":null,"errorMessage":"Reaching Duo has failed with error: [{}]","messagePattern":"Reaching Duo has failed with error: \\[(.+?)\\]","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"support/cas-server-support-duo-core/src/main/java/org/apereo/cas/adaptors/duo/authn/BaseDuoSecurityAuthenticationService.java","lineNumber":124,"sourceCode":"                if (status == DuoSecurityUserAccountStatus.ENROLL) {\n                    val enrollUrl = response.get(RESULT_KEY_ENROLL_PORTAL_URL).asString();\n                    account.setEnrollPortalUrl(enrollUrl);\n                }\n            } else {\n                val code = result.get(RESULT_KEY_CODE).asInt();\n                if (code > RESULT_CODE_ERROR_THRESHOLD) {\n                    LOGGER.warn(\"Duo returned a failure response with code: [{}]. Duo will be considered unavailable\",\n                        result.get(RESULT_KEY_MESSAGE));\n                    throw new DuoSecurityException(\"Duo returned code %s: %s\".formatted(code, result.get(RESULT_KEY_MESSAGE)));\n                }\n                LOGGER.warn(\"Duo returned an Invalid response with message [{}] and detail [{}] \"\n                        + \"when determining user account. This maybe a configuration error in the admin request and Duo will \"\n                        + \"still be considered available.\",\n                    result.hasNonNull(RESULT_KEY_MESSAGE) ? result.get(RESULT_KEY_MESSAGE).asString() : StringUtils.EMPTY,\n                    result.hasNonNull(RESULT_KEY_MESSAGE_DETAIL) ? result.get(RESULT_KEY_MESSAGE_DETAIL).asString() : StringUtils.EMPTY);\n            }\n        } catch (final Exception e) {\n            LOGGER.warn(\"Reaching Duo has failed with error: [{}]\", e.getMessage(), e);\n            account.setStatus(DuoSecurityUserAccountStatus.UNAVAILABLE);\n        }\n\n        userAccountCachedMap.put(account.getUsername(), account);\n        LOGGER.debug(\"Fetched and cached duo user account [{}]\", account);\n        return account;\n    }\n\n    @Override\n    public Optional<DuoSecurityAdminApiService> getAdminApiService() {\n        if (StringUtils.isNotBlank(properties.getDuoAdminIntegrationKey()) && StringUtils.isNotBlank(properties.getDuoAdminSecretKey())) {\n            return Optional.of(new DefaultDuoSecurityAdminApiService(this.httpClient, properties));\n        }\n        return Optional.empty();\n    }\n\n    protected abstract DuoSecurityAuthenticationResult authenticateInternal(Credential credential) throws Exception;\n","sourceCodeStart":106,"sourceCodeEnd":142,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/support/cas-server-support-duo-core/src/main/java/org/apereo/cas/adaptors/duo/authn/BaseDuoSecurityAuthenticationService.java#L106-L142","documentation":"getUserAccount catches any Exception thrown while contacting Duo and logs 'Reaching Duo has failed with error: [{}]' at WARN, then marks the user account status as UNAVAILABLE and caches it. This means CAS could not reach Duo at all (or the request threw), so Duo is treated as down rather than failing authentication outright.","triggerScenarios":"Network failure, DNS failure, TLS error, connection timeout, or any runtime exception during the Duo API HTTP call inside getUserAccount; e.getMessage() of that exception is what appears in the log.","commonSituations":"Duo API host unreachable from the CAS server (firewall/proxy), invalid api-host DNS name, expired/rotated secret keys causing client errors, or transient network outages; users then see duo unavailable or MFA bypass behavior depending on policy.","solutions":["Check network connectivity/proxy settings from the CAS host to the Duo api-host (curl the host)","Verify DNS and TLS trust for api-xxxxx.duosecurity.com","Confirm duo api-host, integration key and secret key are correct and current","Clear the cached user account (userAccountCachedMap) or restart after fixing connectivity, since the UNAVAILABLE status is cached","Consider configuring fail-open/fail-closed MFA policy for the outage scenario"],"exampleFix":"// before\ncas.authn.mfa.duo[0].api-host=api-wrong.duosecurity.com\n// after\ncas.authn.mfa.duo[0].api-host=api-xxxxxxxx.duosecurity.com","handlingStrategy":"retry","validationCode":"// reachability check before auth flow\nval host = new URL(duoProperties.getApiHost());\nvar reachable = InetAddress.getByName(host.getHost()).isReachable(3000);","typeGuard":null,"tryCatchPattern":"try { return duo.getUserAccount(username); } catch (Exception e) { LOGGER.warn(\"Duo unreachable: {}\", e.getMessage(), e); return DuoSecurityUserAccountStatus.UNAVAILABLE; /* then retry with backoff */ }","preventionTips":["Open firewall/proxy egress to Duo api-host","Monitor CAS-to-Duo connectivity","Remember UNAVAILABLE is cached — clear/restart after fixing network","Configure MFA fail-open/closed policy deliberately"],"tags":["duo","mfa","network","connectivity"],"backgroundTag":"network-request-failed","analyzedSha":"e7288fc434b4f4505b8452e1a57e8fb3111bb863","analyzedAt":"2026-09-08T15:39:16.015Z","contentChangedAt":"2026-09-08T15:39:16.015Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}