apereo/cas · error
Failed to save google authenticator account
Error message
Failed to save google authenticator account
What it means
RestGoogleAuthenticatorTokenCredentialRepository.update() posts account changes to the configured REST endpoint. When the HTTP call throws or returns an unexpected response the exception is logged and this warning is emitted, and the method returns null, meaning the save was NOT persisted.
Solutions
- Check the surrounding logged stack trace (LoggingUtils.error) for the root cause — connection refused vs HTTP error vs auth failure
- Verify cas.authn.mfa.gauth.rest.url and REST endpoint credentials are correct and the endpoint is reachable from CAS (curl it)
- Inspect and fix the endpoint's handling of the account payload (method, content type, serialization)
- Add health checks/retries on the REST service so transient outages are caught before account updates fail
Example fix
// before cas.authn.mfa.gauth.rest.url=https://otp.internal.example.org/missingEndpoint // after cas.authn.mfa.gauth.rest.url=https://otp.internal.example.org/api/accounts
Defensive patterns
Strategy: retry
Validate before calling
// verify the REST endpoint before issuing account updates boolean up = HttpUtils.areSettingsHttpsOnlyOk(...) /* or */ curl -fsS $CAS_GAUTH_REST_URL/health;
Try / catch
try {
result = repository.save(account);
if (result == null) { /* save silently failed — inspect logs and retry */ }
} catch (Exception e) {
// network/endpoint failure: retry with backoff
} Prevention
- Health-check the REST endpoint in deployment pipelines
- Validate cas.authn.mfa.gauth.rest.url and credentials
- Treat a null return from save() as failure even though no exception is thrown
- Monitor inter-service connectivity/firewall rules
When it happens
Trigger: Calling save()/update() when the REST endpoint (cas.authn.mfa.gauth.rest.url) is down, returns a non-success status, rejects the payload, or the connection times out; exceptions inside the try block are swallowed and reduced to this warning.
Common situations: REST endpoint misconfigured or unreachable in clustered deployments; endpoint auth (basic auth credentials) missing or wrong; backend service rejects the JSON payload after an API change; network/firewall blocking inter-service calls.
Understand the failure class
Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Unable to successfully fetch JWKS resource from
- Unable to accept response status
- <policy status exception>
- No credentials can be extracted to authenticate the REST…
- Unable to get entity from MDQ server and a backup file does…
AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08).
Data as JSON: /api/errors/f1922f95188ea84b.
Report an issue: GitHub.
Appendix: source
Thrown at support/cas-server-support-gauth-core/src/main/java/org/apereo/cas/gauth/credential/RestGoogleAuthenticatorTokenCredentialRepository.java:254
.method(HttpMethod.POST)
.url(rest.getUrl())
.headers(headers)
.build();
response = HttpUtils.execute(exec);
if (response != null) {
val status = HttpStatus.valueOf(response.getCode());
if (status.is2xxSuccessful()) {
LOGGER.debug("Posted google authenticator account successfully");
return account;
}
}
} catch (final Exception e) {
LoggingUtils.error(LOGGER, e);
} finally {
HttpUtils.close(response);
}
LOGGER.warn("Failed to save google authenticator account");
return null;
}
@Override
public void deleteAll() {
val rest = gauth.getRest();
HttpResponse response = null;
try {
val exec = HttpExecutionRequest.builder()
.basicAuthPassword(rest.getBasicAuthPassword())
.basicAuthUsername(rest.getBasicAuthUsername())
.method(HttpMethod.GET)
.url(rest.getUrl())
.headers(rest.getHeaders())
.build();
response = HttpUtils.execute(exec);
} finally {
HttpUtils.close(response);View on GitHub (pinned to e7288fc434)