apereo/cas · error · AccountLockedException

Captcha value does not match, or CAS cannot unlock the…

Error message

Captcha value does not match, or CAS cannot unlock the account for 

What it means

AccountLockedException thrown by AccountUnlockStatusAction when either the captcha value entered by the user does not equal the captcha value stored in conversation scope, or the PasswordManagementService.unlockAccount call returns false. Both conditions must succeed for the account unlock to proceed.

Solutions

  1. Restart the unlock flow so a fresh captcha is generated, and enter it exactly as shown (comparison is case-sensitive equals).
  2. Check the configured PasswordManagementService (e.g. LDAP/JDBC PM handler) actually supports unlocking and the account exists in the backend.
  3. Verify session/conversation state is preserved (no load-balancer dropping sticky sessions, cookies enabled).
  4. Inspect the error logged by LoggingUtils to distinguish captcha mismatch from unlockAccount returning false.

Example fix

// before
if (!givenValue.equals(providedValue) || !passwordManagementService.unlockAccount(credential)) { throw ... }
// after (captive, case-insensitive compare)
if (!StringUtils.equalsIgnoreCase(givenValue, providedValue) || !passwordManagementService.unlockAccount(credential)) { throw ... }
Defensive patterns

Strategy: validation

Validate before calling

// Pre-check captcha and unlock eligibility
if (!Objects.equals(givenCaptcha, providedCaptcha)) { return error("captcha mismatch"); }
if (!pmService.isAccountLocked(credential)) { return error("account is not locked"); }

Try / catch

try { unlockStatusAction.execute(ctx); } catch (AccountLockedException e) { WebUtils.addErrorMessageToContext(ctx, "screen.account.unlock.fail"); }

Prevention

When it happens

Trigger: During the password-management account-unlock flow, the request parameter captchaValue differs from the conversation-scoped captchaValue, or passwordManagementService.unlockAccount(credential) reports the account could not be unlocked.

Common situations: User mistypes the captcha (case-sensitive comparison); captcha expired because the conversation scope was lost (session timeout, new browser window); the backing account store rejects the unlock (user not found, account not lockable via the configured PM service).

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08). Data as JSON: /api/errors/d36a4745791c8990. Report an issue: GitHub.

Appendix: source

Thrown at support/cas-server-support-pm-webflow/src/main/java/org/apereo/cas/pm/web/flow/actions/AccountUnlockStatusAction.java:37

 * @author Misagh Moayyed
 * @since 6.6.0
 */
@Slf4j
@RequiredArgsConstructor
public class AccountUnlockStatusAction extends BaseCasWebflowAction {

    private final PasswordManagementService passwordManagementService;

    @Override
    protected @Nullable Event doExecuteInternal(final RequestContext requestContext) {
        try {
            val credential = requestContext.getConversationScope().get(Credential.class.getName(), Credential.class);
            LOGGER.debug("Attempting to unlock account for [{}]", credential);
            val givenValue = requestContext.getConversationScope().get("captchaValue", String.class);
            val providedValue = WebUtils.getRequestParameterOrAttribute(requestContext, "captchaValue").orElseThrow();
            LOGGER.debug("Comparing captcha value [{}] with user entry [{}]", givenValue, providedValue);
            if (!givenValue.equals(providedValue) || !passwordManagementService.unlockAccount(credential)) {
                throw new AccountLockedException("Captcha value does not match, or CAS cannot unlock the account for " + credential.getId());
            }
            WebUtils.addInfoMessageToContext(requestContext, "screen.account.unlock.success");
            return success();
        } catch (final Throwable e) {
            WebUtils.addErrorMessageToContext(requestContext, "screen.account.unlock.fail");
            LoggingUtils.error(LOGGER, e);
            return error();
        }
    }
}

View on GitHub (pinned to e7288fc434)