apache/shenyu · error · RuntimeException
Invalid URI construction
Error message
Invalid URI construction: ${e.getMessage()} What it means
setTargetUri rebuilds the request URI as scheme://authority + path and applies it to the request builder. If the resulting string is not a syntactically valid URI, URISyntaxException is wrapped in RuntimeException('Invalid URI construction: ...').
Solutions
- Inspect the wrapped cause message — java.net.URI reports the illegal character and index.
- URL-encode the path before building: UriComponentsBuilder.fromPath(path).build().encode() or URLEncoder for segments.
- Ensure all '{placeholder}' tokens in the path template are replaced before setTargetUri runs.
- Strip illegal characters or convert them to a query string when appropriate.
Example fix
// before
requestBuilder.uri(new URI(base + "/users/{id}".replace("{id}", rawId)));
// after
String encoded = UriComponentsBuilder.fromPath("/users/{id}").buildAndExpand(rawId).encode().toPathString();
requestBuilder.uri(new URI(base + encoded)); Defensive patterns
Strategy: validation
Validate before calling
boolean isBuildableUri(String scheme, String authority, String path) {
try {
new java.net.URI(scheme + "://" + authority + path);
return true;
} catch (java.net.URISyntaxException e) {
return false;
}
} Try / catch
try {
return callback.call(args, ctx);
} catch (RuntimeException e) {
if (e.getMessage() != null && e.getMessage().startsWith("Invalid URI construction")) {
log.error("Bad tool path, illegal characters: {}", e.getCause().getMessage());
return "Invalid target path configured for tool";
}
throw e;
} Prevention
- URL-encode path segments and substitute all '{placeholder}' tokens before the call.
- Build URIs with Spring's UriComponentsBuilder(...).encode() instead of string concat.
- Reject paths containing spaces, braces, or control characters at config time.
- Test each tool's requestConfig path with a real request before publishing.
When it happens
Trigger: The computed path argument contains illegal URI characters (spaces, unencoded braces '{ }', raw unicode, control chars) so that scheme://authority+path fails java.net.URI parsing.
Common situations: Path templates from requestConfig or MCP arguments contain '{param}' placeholders that were never substituted; path built from unescaped user input containing spaces or query fragments with raw characters.
Understand the failure class
Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.
Related errors
- Tool execution timeout or error
- 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/649df61851391c97.
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:589
}
}
/**
* Sets the target URI for the request.
*
* @param requestBuilder the request builder
* @param originExchange the original exchange
* @param path the target path
*/
private void setTargetUri(final ServerHttpRequest.Builder requestBuilder,
final ServerWebExchange originExchange,
final String path) {
try {
final URI oldUri = originExchange.getRequest().getURI();
final String newUriStr = oldUri.getScheme() + "://" + oldUri.getAuthority() + path;
requestBuilder.uri(new URI(newUriStr));
} catch (URISyntaxException e) {
throw new RuntimeException("Invalid URI construction: " + e.getMessage(), e);
}
}
/**
* Creates appropriate response decorator based on protocol type.
*
* @param originExchange the original exchange
* @param sessionId the session identifier
* @param responseFuture the response future
* @param configStr the configuration string (for response template)
* @return the appropriate response decorator
*/
private ServerHttpResponseDecorator createResponseDecorator(final ServerWebExchange originExchange,
final String sessionId,
final CompletableFuture<String> responseFuture,
final String configStr) {
final RequestConfigHelper configHelper = new RequestConfigHelper(configStr);View on GitHub (pinned to 567142e072)