apereo/cas · warning

No ClientInfo could be found. Returning empty ClientInfo…

Error message

No ClientInfo could be found. Returning empty ClientInfo object.

What it means

DefaultClientInfoResolver.resolveFrom reads ClientInfoHolder.getClientInfo(), which is populated by the ClientInfo thread-local filter/interceptor. When no ClientInfo is bound to the current thread (audit executed outside a request handled by that filter), it warns and returns ClientInfo.empty(), so audit records lack client IP/host/user-agent data rather than failing.

Solutions

  1. Ensure the ClientInfoHolderFilter (Inspektr client-info filter) is registered and ordered before audited endpoints in the CAS filter chain.
  2. For non-HTTP threads, populate ClientInfoHolder manually before invoking audited code (ClientInfoHolder.setHeader/clientInfo) and clear it afterward.
  3. Treat the warning as benign for background jobs where client info is inherently absent.
  4. In tests, set up ClientInfoHolder in the test setup or ignore this warning in test logs.

Example fix

// before: background thread audits with no client info
executor.submit(() -> ticketService.someAuditedOperation());

// after: supply client info for the thread
executor.submit(() -> {
    ClientInfoHolder.setClientInfo(new ClientInfo("127.0.0.1", "localhost"));
    try {
        ticketService.someAuditedOperation();
    } finally {
        ClientInfoHolder.clearClientInfo();
    }
});
Defensive patterns

Strategy: try-catch

Validate before calling

ClientInfo clientInfo = ClientInfoHolder.getClientInfo();
if (clientInfo == null) {
    ClientInfoHolder.setClientInfo(ClientInfo.empty()); // or a synthetic ClientInfo
}

Try / catch

try {
    auditedService.operation();
} finally {
    if (ClientInfoHolder.getClientInfo() != null) {
        ClientInfoHolder.clearClientInfo();
    }
}

Prevention

When it happens

Trigger: Audit aspect (Inspektr) runs on a code path where the ClientInfoHolderFilter or the thread-local population step never ran: background/scheduled jobs, direct service invocations in tests, asynchronous threads spawned from requests, or the client-info filter not registered in the filter chain.

Common situations: CAS deployments missing the clientInfoHolder filter configuration; audit of ticket-expiration cleanup jobs and other non-HTTP executors; unit/integration tests calling audited services directly; custom filters reordering so the client-info filter runs after the audited code.

Understand the failure class

Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.

Related errors


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

Appendix: source

Thrown at core/cas-server-core-audit-api/src/main/java/org/apereo/inspektr/common/spi/DefaultClientInfoResolver.java:25

import module java.base;
import org.aspectj.lang.JoinPoint;
import org.jspecify.annotations.Nullable;

/**
 * Default implementation that gets it from the {@link ThreadLocal}.
 *
 * @author Scott Battaglia
 * @since 1.0
 */
@Slf4j
public class DefaultClientInfoResolver implements ClientInfoResolver {
    @Override
    public ClientInfo resolveFrom(final JoinPoint joinPoint, @Nullable final Object retVal) {
        val clientInfo = ClientInfoHolder.getClientInfo();
        if (clientInfo != null) {
            return resolveClientInfo(clientInfo);
        }
        LOGGER.warn("No ClientInfo could be found. Returning empty ClientInfo object.");
        return ClientInfo.empty();
    }

    protected ClientInfo resolveClientInfo(final ClientInfo clientInfo) {
        return clientInfo;
    }
}

View on GitHub (pinned to e7288fc434)