theonedev/onedev · warning · ExplicitException

Conversation context lost

Error message

Conversation context lost

What it means

OneDev's AI chat service streams tool calls from the LLM back to the browser over a WebSocket. When the model returns tool execution requests, the service looks up the originating WebSocket connection by session id and page key; if the connection is gone or closed, it aborts with this ExplicitException because the tool result can no longer be delivered to the client.

Source

Thrown at server-core/src/main/java/io/onedev/server/ai/DefaultChatService.java:317

					@Override
					public void onCompleteResponse(ChatResponse completeResponse) {	
						ThreadContext.bind(subject);
						var responding = getResponding(sessionId, chatId, requestId);
						if (responding != null && responding.getContent() != null && thinkingBlockOpen) {
							responding.content = ensureThinkingClosed(responding.getContent());
							webSocketService.notifyObservableChange(Chat.getPartialResponseObservable(chatId), null);
						}
						sessionService.runAsync(() -> {
							try {
								var aiMessage = completeResponse.aiMessage();
								if (aiMessage.hasToolExecutionRequests()) {
									langchain4jMessages.add(aiMessage);
									var toolRequests = aiMessage.toolExecutionRequests();
									var connectionRegistry = WebSocketSettings.Holder.get(application).getConnectionRegistry();
									var connection = connectionRegistry.getConnection(application, sessionId, pageKey);
									if (connection == null || !connection.isOpen())
										throw new ExplicitException("Conversation context lost");
									for (var toolRequest: toolRequests) {
										if (responseFuture.isDone())										
											return;
										String toolName = toolRequest.name();
										try {
											var toolExecution = new AiToolExecution(toolName, ToolUtils.getToolArguments(toolRequest));
											connection.sendMessage(toolExecution);
											var toolExecutionFuture = toolExecution.getFuture();
											if (toolExecutionFuture == null)
												throw new ExplicitException("Tool not found: " + toolName);
											while (true) {
												try {
													var toolExecutionResult = toolExecutionFuture.get(1, TimeUnit.SECONDS);
													toolExecutionResult.addToMessages(langchain4jMessages, toolRequest);
													break;
												} catch (TimeoutException e) {
													if (responseFuture.isDone())
														return;

View on GitHub (pinned to d44925c47c)

Solutions

  1. Keep the chat page open until the AI response finishes; check the browser console for WebSocket disconnects before retrying
  2. Retry the conversation from a fresh chat page so a new WebSocket connection and pageKey are established
  3. If behind a reverse proxy, raise proxy read/send timeouts and enable WebSocket upgrade passthrough
  4. Check server logs for earlier WebSocket errors (connection registry drops) and adjust WebSocket idle timeout settings

Example fix

// before: user closes page mid-stream -> exception
// after: client keeps the chat panel mounted and reconnects before sending a message
// (server-side guard in calling code)
try {
    chatService.chat(...);
} catch (ExplicitException e) {
    if (e.getMessage().equals("Conversation context lost")) {
        reconnectWebSocketAndResend();
    }
}
Defensive patterns

Strategy: try-catch

Validate before calling

// client-side before sending a chat message
if (!ws || ws.readyState !== WebSocket.OPEN) reconnectChatSocket();

Try / catch

try {
    chatService.chat(chatId, prompt);
} catch (ExplicitException e) {
    if ("Conversation context lost".equals(e.getMessage())) {
        // reopen chat page / re-establish WebSocket and resend
    }
}

Prevention

When it happens

Trigger: onCompleteResponse receives an AI message containing tool execution requests while connectionRegistry.getConnection(application, sessionId, pageKey) returns null or a closed connection — i.e. the user closed/refreshed the chat page or the WebSocket dropped mid-conversation.

Common situations: User navigates away or reloads the page while the AI response is still streaming; WebSocket idle timeouts or proxy/load-balancer disconnects; server restart between request and tool-call phase; session id or page key changed after a page re-render.

Understand the failure class

Background: ECONNREFUSED and "connection refused" / "could not connect to server" errors: what they mean and how to fix them — this error's family across 44 libraries.

Related errors


AI-assisted analysis of theonedev/onedev@d44925c47c (2026-09-06). Data as JSON: /api/errors/41d488616661a4a6. Report an issue: GitHub.