spring-projects/spring-ai · warning

Server does not recognize session + invalidSession.sessionId

Error message

Server does not recognize session + invalidSession.sessionId() + . Invalidating.

What it means

A warning logged in WebClientStreamableHttpTransport.handleException when the server responds with McpTransportSessionNotFoundException, meaning the HTTP session id this client is using is no longer valid on the server (expired, restarted server, or load-balanced to a node without session state). The transport invalidates the stale session and immediately creates a fresh one, then re-dispatches through the configured exception handler.

Source

Thrown at mcp/transport/mcp-spring-webflux/src/main/java/org/springframework/ai/mcp/client/webflux/transport/WebClientStreamableHttpTransport.java:204

					})
					.then();
		return new DefaultMcpTransportSession(onClose);
	}

	@Override
	public void setExceptionHandler(Consumer<Throwable> handler) {
		logger.debug("Exception handler registered");
		this.exceptionHandler.set(handler);
	}

	private void handleException(Throwable t) {
		if (logger.isDebugEnabled()) {
			logger.debug("Handling exception for session " + sessionIdOrPlaceholder(this.activeSession.get()), t);
		}
		if (t instanceof McpTransportSessionNotFoundException) {
			McpTransportSession<?> invalidSession = this.activeSession.getAndSet(createTransportSession());
			if (logger.isWarnEnabled()) {
				logger.warn("Server does not recognize session " + invalidSession.sessionId() + ". Invalidating.");
			}
			invalidSession.close();
		}
		Consumer<Throwable> handler = this.exceptionHandler.get();
		if (handler != null) {
			handler.accept(t);
		}
	}

	@Override
	public Mono<Void> closeGracefully() {
		return Mono.defer(() -> {
			logger.debug("Graceful close triggered");
			McpTransportSession<Disposable> currentSession = this.activeSession
				.getAndSet(ClosedMcpTransportSession.INSTANCE);
			if (currentSession != null) {
				return Mono.from(currentSession.closeGracefully());
			}

View on GitHub (pinned to 98a7beda4f)

Solutions

  1. Ensure the exception handler / retry logic re-issues the failed request after the session is recreated
  2. Configure the MCP server with a longer session TTL or session persistence for long-lived clients
  3. Enable sticky sessions or shared session state when running multiple server instances behind a load balancer
  4. Treat this warning as expected recovery — if requests keep failing, check that reconnect logic resends the initialize handshake where required

Example fix

// before
transport.connect();
client.callTool(request); // fails if session was invalidated mid-flight
// after
transport.connect();
client.callTool(request)
    .retryWhen(Retry.backoff(3, Duration.ofMillis(500))
        .filter(t -> t instanceof McpTransportSessionNotFoundException));
Defensive patterns

Strategy: retry

Try / catch

client.callTool(req)
    .retryWhen(reactor.util.retry.Retry.backoff(3, Duration.ofMillis(500))
        .filter(e -> e instanceof McpTransportSessionNotFoundException))
    .block();

Prevention

When it happens

Trigger: MCP server restarted or evicted the session (mcp-session-id no longer recognized); sticky sessions not configured behind a load balancer; server session timeout shorter than client lifetime; a 404/session-not-found HTTP response mapped to McpTransportSessionNotFoundException during a stream/request.

Common situations: Rolling deployments of the MCP server; server-side session TTL expiry during long-running client connections; multi-instance deployments without shared session storage.

Related errors


AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11). Data as JSON: /api/errors/0cdbc988d0ed1e09. Report an issue: GitHub.