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

  1. Inspect the wrapped cause message — java.net.URI reports the illegal character and index.
  2. URL-encode the path before building: UriComponentsBuilder.fromPath(path).build().encode() or URLEncoder for segments.
  3. Ensure all '{placeholder}' tokens in the path template are replaced before setTargetUri runs.
  4. 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

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


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)