apereo/cas · warning · FailedLoginException

Thread interrupted while waiting for connection to validate…

Error message

Thread interrupted while waiting for connection to validate SPNEGO Token

What it means

While waiting to borrow a connection from the SPNEGO authentications pool, the calling thread received InterruptedException; the handler converts this into FailedLoginException. It indicates the thread was interrupted during pool.poll(), typically during server shutdown or executor termination.

Solutions

  1. Retry the authentication once the server is stable; this is usually transient during shutdown.
  2. Ensure clean shutdown ordering so login requests complete before pool/executor teardown.
  3. Check for overly aggressive request-timeout or thread-interruption policies in the servlet container/proxy.
  4. Investigate thread leaks that keep threads blocked in the pool and force interrupt-based cleanup.
Defensive patterns

Strategy: retry

Try / catch

try {
    return handler.authenticate(credential);
} catch (FailedLoginException e) {
    if (e.getMessage().contains("Thread interrupted")) {
        LOGGER.warn("SPNEGO auth interrupted; retry after shutdown/deploy completes");
    }
    throw e;
}

Prevention

When it happens

Trigger: CAS shutdown/redeployment while SPNEGO logins are in flight; the request thread's executor is shutting down; manual thread interruption (e.g. request timeout killer) hitting a thread blocked in poll().

Common situations: Graceful shutdown under load; container orchestrator terminating pods; long-running blocked threads interrupted by timeouts.

Understand the failure class

Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.

Related errors


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

Appendix: source

Thrown at support/cas-server-support-spnego/src/main/java/org/apereo/cas/support/spnego/authentication/handler/support/JcifsSpnegoAuthenticationHandler.java:68

        if (!spnegoProperties.isNtlmAllowed() && spnegoCredential.isNtlm()) {
            throw new FailedLoginException("NTLM not allowed");
        }

        try {
            LOGGER.debug("Waiting for connection to validate SPNEGO Token");
            val poolTimeoutInMilliseconds = Beans.newDuration(spnegoProperties.getPoolTimeout()).toMillis();
            val authentications = authenticationsPool.poll(poolTimeoutInMilliseconds, TimeUnit.MILLISECONDS);
            if (authentications != null) {
                try {
                    return doInternalAuthentication(authentications, spnegoCredential, service);
                } finally {
                    authenticationsPool.add(authentications);
                    LOGGER.debug("Returned connection to pool");
                }
            }
            throw new FailedLoginException("Cannot get connection from pool to validate SPNEGO Token");
        } catch (final InterruptedException e) {
            throw new FailedLoginException("Thread interrupted while waiting for connection to validate SPNEGO Token");
        }
    }

    protected AuthenticationHandlerExecutionResult doInternalAuthentication(final List<Authentication> authentications,
                                                                            final SpnegoCredential spnegoCredential, final Service service) throws Throwable {
        var principal = (java.security.Principal) null;
        var nextToken = (byte[]) null;
        val it = authentications.iterator();
        while (nextToken == null && it.hasNext()) {
            try {
                val authentication = it.next();
                authentication.reset();
                LOGGER.debug("Processing SPNEGO authentication");
                authentication.process(spnegoCredential.getInitToken());
                principal = authentication.getPrincipal();
                LOGGER.debug("Authenticated SPNEGO principal [{}]. Retrieving the next token for authentication...",
                    Optional.ofNullable(principal).map(java.security.Principal::getName).orElse(null));
                nextToken = authentication.getNextToken();

View on GitHub (pinned to e7288fc434)