apache/shenyu · error · RuntimeException
Tool execution timeout or error
Error message
Tool execution timeout or error: ${e.getMessage()} What it means
executeToolCall performs the decorated downstream exchange for the tool, often with a timeout guard. If execution throws or times out, it cleans up temporary MCP sessions and rethrows as RuntimeException('Tool execution timeout or error: ...'). It distinguishes the execution phase failure from earlier setup failures in call().
Solutions
- Inspect the wrapped cause: TimeoutException means increase the tool execution timeout or speed up the backend; IOException means connectivity.
- Verify the target service is up and the gateway route (selector/rule) matches the configured path.
- Increase the MCP tool execution timeout configuration for slow backends.
- Retest with a simple tool call to isolate whether the failure is tool-specific.
Defensive patterns
Strategy: try-catch
Try / catch
try {
return callback.call(args, ctx);
} catch (RuntimeException e) {
Throwable c = e.getCause();
if (c instanceof java.util.concurrent.TimeoutException) {
// raise timeout or return graceful 'tool too slow' response
} else if (c instanceof java.io.IOException) {
// backend unreachable: check service health, maybe retry
}
throw e;
} Prevention
- Set MCP tool execution timeouts comfortably above backend p99 latency.
- Monitor backend health; unhealthy upstreams will surface as this error.
- Verify selector/rule routing matches the configured tool path before enabling a tool.
- Use persistent MCP sessions to avoid cleanup-related edge cases.
When it happens
Trigger: The reactive tool execution inside executeToolCall times out or the downstream HTTP call errors (connection refused, 5xx, blocked selector/rule), while a valid session and config were already established.
Common situations: Backend service behind the gateway is down or slow; configured timeout too short for a long-running tool; wrong path in requestConfig leading to 404/500 from the gateway itself.
Understand the failure class
Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- Invalid URI construction
- Request body must not be empty
- Tool execution failed
- Tool definition must be of type ShenyuToolDefinition, got
- Request configuration cannot be empty
AI-assisted analysis of apache/shenyu@567142e072 (2026-09-12).
Data as JSON: /api/errors/83eeaaf2da2abc49.
Report an issue: GitHub.
Appendix: source
Thrown at shenyu-plugin/shenyu-plugin-mcp-server/src/main/java/org/apache/shenyu/plugin/mcp/server/callback/ShenyuToolCallback.java:282
}
})
.subscribe();
// Wait for the response with timeout
try {
final String result = responseFuture.get(DEFAULT_TIMEOUT_SECONDS, TimeUnit.SECONDS);
LOG.debug("Tool call completed successfully for session: {}", sessionId);
return result;
} catch (Exception e) {
LOG.error("Timeout or error waiting for response for session {}: {}", sessionId, e.getMessage(), e);
// Ensure cleanup on error for temporary sessions
if (isTemporarySession) {
LOG.debug("Emergency cleanup of temporary session on error: {}", sessionId);
ShenyuMcpExchangeHolder.remove(sessionId);
}
throw new RuntimeException("Tool execution timeout or error: " + e.getMessage(), e);
}
}
/**
* Builds a decorated ServerWebExchange for tool execution.
* <p>Creates a new exchange with modified request (method, path, headers, body),
* response decorator based on protocol type, and updated Shenyu context and metadata.</p>
*
* @param originExchange the original exchange
* @param responseFuture the future for capturing response
* @param sessionId the session identifier
* @param configStr the request configuration
* @param input the tool input parameters
* @return the decorated exchange ready for execution
*/
private ServerWebExchange buildDecoratedExchange(final ServerWebExchange originExchange,
final CompletableFuture<String> responseFuture,
final String sessionId,View on GitHub (pinned to 567142e072)