apereo/cas · warning · FailedLoginException
Account removal is not verified for
Error message
Account removal is not verified for [{}] What it means
Before deleting a device, the delete action requires that a prior verified token marked the removal as confirmed (isAccountRemovalVerified). When false, the user is attempting removal without completing the verification step; this warning is logged and FailedLoginException is thrown.
Solutions
- Restart the device-removal flow from the start so the OTP verification step runs before deletion
- Start a new webflow execution instead of resuming an old/expired one
- If customizing the flow, ensure accountRemovalVerified(...) is invoked in the verification state before the delete action executes
- Confirm flow/session scope persistence so the verified flag survives between steps
Defensive patterns
Strategy: validation
Validate before calling
// ensure the removal-verification step ran before delete
boolean verified = requestContext.getFlowScope().contains("googleAuthenticatorAccountRemovalVerified"); Try / catch
try {
event = action.execute(requestContext);
} catch (FailedLoginException e) {
// send the user back to the token-verification step of removal
} Prevention
- Do not bookmark the delete confirmation screen
- Execute verification state before delete state in custom flows
- Start fresh executions instead of resuming old ones
- Preserve flow scope across the removal steps
When it happens
Trigger: doExecuteInternal guard reached when no successful token validation previously stored the removal-verified flag: direct/back-navigation into the delete step, resumed flow execution, or skipped verification state.
Common situations: User refreshes or back-navigates to the delete confirmation screen; expired or reused webflow execution; customized flow bypassing the verification state; lost flow scope between steps.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Account registration is not verified for
- Authorization of OTP token
- Unable to determine google authenticator account
- State [ : : ] does not have a matching transition for
- Unknown Duo Security authentication attempt
AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08).
Data as JSON: /api/errors/8fb47b551108fa44.
Report an issue: GitHub.
Appendix: source
Thrown at support/cas-server-support-gauth-core/src/main/java/org/apereo/cas/gauth/web/flow/GoogleAuthenticatorDeleteAccountAction.java:62
if (BooleanUtils.isTrue(validate)) {
val token = requestParameters.getRequired(GoogleAuthenticatorSaveRegistrationAction.REQUEST_PARAMETER_TOKEN, String.class);
val authentication = WebUtils.getAuthentication(requestContext);
val principal = authentication.getPrincipal().getId();
LOGGER.debug("Validating account [{}] with token [{}] for principal [{}]", accountId, token, principal);
val tokenCredential = new GoogleAuthenticatorTokenCredential(token, accountId);
val validatedToken = validator.validate(authentication, tokenCredential);
if (validatedToken != null) {
LOGGER.debug("Validated OTP token [{}] successfully for [{}]", validatedToken, principal);
accountRemovalVerified(requestContext, account);
return success();
}
LOGGER.warn("Authorization of OTP token [{}] has failed", token);
throw new FailedLoginException("Failed to authenticate code " + token);
}
if (!isAccountRemovalVerified(requestContext, account)) {
LOGGER.warn("Account removal is not verified for [{}]", account.getId());
throw new FailedLoginException("Unauthorized account removal attempt " + account.getId());
}
LOGGER.debug("Deleting account [{}]", account.getId());
repository.delete(account.getId());
return success();
}
protected void accountRemovalVerified(final RequestContext requestContext, final OneTimeTokenAccount account) {
account.getProperties().add(ACCOUNT_PROPERTY_REMOVAL_VERIFIED);
repository.update(account);
}
protected boolean isAccountRemovalVerified(final RequestContext requestContext, final OneTimeTokenAccount account) {
return account.getProperties().contains(ACCOUNT_PROPERTY_REMOVAL_VERIFIED);
}
}
View on GitHub (pinned to e7288fc434)