spring-projects/spring-ai · error · IllegalStateException

MessageEndpoint must be set

Error message

MessageEndpoint must be set

What it means

WebMvcSseServerTransportProvider.Builder.build() validates required builder fields before instantiating the provider. messageEndpoint (the servlet path where clients POST JSON-RPC messages) is mandatory; if it was never set the builder throws IllegalStateException("MessageEndpoint must be set"). The javadoc also notes jsonMapper must be set (otherwise a default mapper is used).

Source

Thrown at mcp/transport/mcp-spring-webmvc/src/main/java/org/springframework/ai/mcp/server/webmvc/transport/WebMvcSseServerTransportProvider.java:676

		 * @param securityValidator The security validator to use. Must not be null.
		 * @return this builder instance
		 * @throws IllegalArgumentException if securityValidator is null
		 */
		public Builder securityValidator(ServerTransportSecurityValidator securityValidator) {
			Assert.notNull(securityValidator, "Security validator must not be null");
			this.securityValidator = securityValidator;
			return this;
		}

		/**
		 * Builds a new instance of WebMvcSseServerTransportProvider with the configured
		 * settings.
		 * @return A new WebMvcSseServerTransportProvider instance
		 * @throws IllegalStateException if jsonMapper or messageEndpoint is not set
		 */
		public WebMvcSseServerTransportProvider build() {
			if (this.messageEndpoint == null) {
				throw new IllegalStateException("MessageEndpoint must be set");
			}
			return new WebMvcSseServerTransportProvider(
					this.jsonMapper == null ? McpJsonDefaults.getMapper() : this.jsonMapper, this.baseUrl,
					this.messageEndpoint, this.sseEndpoint, this.keepAliveInterval, this.contextExtractor,
					this.securityValidator);
		}

	}

}

View on GitHub (pinned to 98a7beda4f)

Solutions

  1. Add .messageEndpoint("/message") (or your chosen POST endpoint path) to the builder chain before build().
  2. Also set baseUrl and sseEndpoint as needed so clients get correct SSE and POST URLs.
  3. If a default is acceptable, wrap the builder in a helper that applies standard endpoint values when unset.

Example fix

// before
WebMvcSseServerTransportProvider provider = WebMvcSseServerTransportProvider.builder()
    .sseEndpoint("/sse")
    .build(); // throws

// after
WebMvcSseServerTransportProvider provider = WebMvcSseServerTransportProvider.builder()
    .sseEndpoint("/sse")
    .messageEndpoint("/message")
    .build();
Defensive patterns

Strategy: validation

Validate before calling

// Before building the provider
Objects.requireNonNull(baseUrl, "baseUrl must be set");
Objects.requireNonNull(messageEndpoint, "messageEndpoint must be set");
Objects.requireNonNull(sseEndpoint, "sseEndpoint must be set");

Try / catch

try {
    provider = builder.build();
} catch (IllegalStateException e) {
    if (e.getMessage().contains("MessageEndpoint must be set")) {
        builder.messageEndpoint("/message");
        provider = builder.build();
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: Calling WebMvcSseServerTransportProvider.builder()...build() without invoking .messageEndpoint(String), then deploying/starting the SSE server transport.

Common situations: Copy-pasting a builder chain and omitting the messageEndpoint step; conditional configuration that skips the endpoint assignment; confusing baseUrl with messageEndpoint and setting only one.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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