{"record":{"id":"83df3163854e8059","repo":"spring-projects/spring-ai","slug":"failed-to-serialize-initresponse","errorCode":null,"errorMessage":"Failed to serialize initResponse","messagePattern":"Failed to serialize initResponse","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"mcp/transport/mcp-spring-webflux/src/main/java/org/springframework/ai/mcp/server/webflux/transport/WebFluxStreamableServerTransportProvider.java","lineNumber":474,"sourceCode":"\t\t}\n\t\tvar typeReference = new TypeRef<McpSchema.InitializeRequest>() {\n\t\t};\n\t\tMcpSchema.InitializeRequest initializeRequest = this.jsonMapper.convertValue(jsonrpcRequest.params(),\n\t\t\t\ttypeReference);\n\t\tMcpStreamableServerSession.McpStreamableServerSessionInit init = this.sessionFactory\n\t\t\t.startSession(initializeRequest);\n\t\tthis.sessions.put(init.session().getId(), init.session());\n\t\tif (this.sessionIdleTimeout != null) {\n\t\t\tthis.sessionLastAccessTimes.put(init.session().getId(), Instant.now());\n\t\t}\n\t\treturn init.initResult().map(initializeResult -> {\n\t\t\tMcpSchema.JSONRPCResponse jsonrpcResponse = new McpSchema.JSONRPCResponse(McpSchema.JSONRPC_VERSION,\n\t\t\t\t\tjsonrpcRequest.id(), initializeResult, null);\n\t\t\ttry {\n\t\t\t\treturn this.jsonMapper.writeValueAsString(jsonrpcResponse);\n\t\t\t}\n\t\t\tcatch (IOException e) {\n\t\t\t\tlogger.warn(\"Failed to serialize initResponse\", e);\n\t\t\t\tthrow Exceptions.propagate(e);\n\t\t\t}\n\t\t})\n\t\t\t.flatMap(initResult -> ServerResponse.ok()\n\t\t\t\t.contentType(MediaType.APPLICATION_JSON)\n\t\t\t\t.header(HttpHeaders.MCP_SESSION_ID, init.session().getId())\n\t\t\t\t.bodyValue(initResult));\n\t}\n\n\t/**\n\t * Records the current time as the last access time for the given session, so that an\n\t * active session is not evicted as idle. No-op when idle eviction is disabled or the\n\t * session is no longer tracked.\n\t * @param sessionId the id of the session that was just accessed\n\t */\n\tprivate void touchSession(String sessionId) {\n\t\tif (this.sessionIdleTimeout != null) {\n\t\t\tthis.sessionLastAccessTimes.computeIfPresent(sessionId, (id, lastAccess) -> Instant.now());","sourceCodeStart":456,"sourceCodeEnd":492,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/mcp/transport/mcp-spring-webflux/src/main/java/org/springframework/ai/mcp/server/webflux/transport/WebFluxStreamableServerTransportProvider.java#L456-L492","documentation":"A warning plus rethrown exception in WebFluxStreamableServerTransportProvider.handleInitResponse when serializing the JSONRPCResponse containing the InitializeResult fails with an IOException. The initialize handshake cannot complete, so the error propagates to the HTTP layer and the client's initialize call fails. This almost always means a component inside InitializeResult cannot be serialized to JSON.","triggerScenarios":"A custom capability, implementation info, or tool schema inside InitializeResult is not JSON-serializable (e.g. non-POJO objects, self-referencing structures, unsupported types); the JsonMapper misconfigured; serialization produced invalid state.","commonSituations":"Custom McpServerFeatures.SyncToolSpecification returning objects Jackson can't map; registering capabilities with exotic types; bugs in custom JsonMapper configuration.","solutions":["Inspect the IOException cause to find which field of InitializeResult fails to serialize","Ensure all objects in serverInfo, capabilities, and tool schemas are simple JSON-mappable POJOs","Avoid circular references or use DTOs for custom capability payloads","Verify the configured JsonMapper (e.g. Jackson) handles all registered types"],"exampleFix":"// before\nreturn new InitializeResult(PROTOCOL_VERSION,\n    new ServerCapabilities.Builder().build(),\n    Map.of(\"customObj\", new SomeNonSerializableObject()), // breaks serialization\n    serverInfo, instructions);\n// after\nreturn new InitializeResult(PROTOCOL_VERSION,\n    new ServerCapabilities.Builder().build(),\n    Map.of(\"custom\", Map.of(\"key\", \"value\")), // JSON-mappable\n    serverInfo, instructions);","handlingStrategy":"try-catch","validationCode":"// pre-validate InitializeResult payload is JSON-mappable\nnew ObjectMapper().writeValueAsString(initializeResult); // throws early if not","typeGuard":null,"tryCatchPattern":"try {\n    provider.handleInitRequest(...);\n} catch (Exception e) {\n    Throwable root = Exceptions.unwrap(e);\n    log.error(\"Initialize failed (serialization?): {}\", root.getMessage(), root);\n}","preventionTips":["Use simple JSON-mappable POJOs in capabilities and instructions","Avoid circular or non-serializable objects in InitializeResult","Test the initialize handshake in CI with the exact JsonMapper configured","Keep custom capability payloads as Maps/records of primitives"],"tags":["mcp","serialization","json","server"],"backgroundTag":"json-serialization-failed","analyzedSha":"98a7beda4f29d80a71c5837eb4053b03a93a46f7","analyzedAt":"2026-09-11T14:15:49.441Z","contentChangedAt":"2026-09-11T14:15:49.441Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}