OpenFeign/feign · error · IOException

URL ' ' couldn't be parsed into a URI

Error message

URL '${request.url()}' couldn't be parsed into a URI

What it means

ApacheHttpClient.execute converts the Feign Request URL into an HttpUriRequest; if the URL string cannot be parsed into a java.net.URI (URISyntaxException), it is rethrown as an IOException with the offending URL in the message. Feign URLs are templates that should be valid URIs, so this indicates malformed URL construction.

Solutions

  1. Log/inspect the URL in the message and fix the illegal character at its source.
  2. URL-encode path and query parameter values before passing them (or rely on Feign's @Param expansion with proper encoding).
  3. Fix the @RequestLine/URL template so placeholders are expanded, not left with literal braces.
  4. Validate the base URL/host configuration for stray whitespace, double slashes, or bad characters.

Example fix

// before
String name = "john doe";
api.getUser(name); // GET /users/john doe -> URISyntaxException
// after
String name = URLEncoder.encode("john doe", StandardCharsets.UTF_8);
api.getUser(name); // GET /users/john%20doe
Defensive patterns

Strategy: validation

Validate before calling

static boolean isUriSafe(String url) {
  try { new java.net.URI(url); return true; } catch (java.net.URISyntaxException e) { return false; }
}
// run before building the Feign request; encode values with URLEncoder if false

Try / catch

try {
  response = feignClient.call(param);
} catch (java.io.IOException e) {
  if (e.getMessage() != null && e.getMessage().contains("couldn't be parsed into a URI")) {
    throw new IllegalArgumentException("Bad URL built from param, encode it first", e);
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling a Feign client where the resolved target URL contains illegal characters (unencoded spaces, '{', '}', '|', non-ASCII characters), an empty path component bug, or a path/query parameter expanded with raw special characters not URL-encoded by the encoder.

Common situations: Passing path variables containing spaces or unencoded reserved characters; building target URLs by string concatenation instead of RequestTemplate; hosting config with a typo (double slashes, missing scheme handled upstream); migrating to ApacheHttpClient which is stricter than other clients.

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 OpenFeign/feign@e2a1e27560 (2026-09-10). Data as JSON: /api/errors/200bf7da2e0e3ff9. Report an issue: GitHub.

Appendix: source

Thrown at httpclient/src/main/java/feign/httpclient/ApacheHttpClient.java:82

  private static final String ACCEPT_HEADER_NAME = "Accept";

  private final HttpClient client;

  public ApacheHttpClient() {
    this(HttpClientBuilder.create().build());
  }

  public ApacheHttpClient(HttpClient client) {
    this.client = client;
  }

  @Override
  public Response execute(Request request, Request.Options options) throws IOException {
    HttpUriRequest httpUriRequest;
    try {
      httpUriRequest = toHttpUriRequest(request, options);
    } catch (URISyntaxException e) {
      throw new IOException("URL '" + request.url() + "' couldn't be parsed into a URI", e);
    }
    HttpResponse httpResponse = client.execute(httpUriRequest);
    return toFeignResponse(httpResponse, request);
  }

  HttpUriRequest toHttpUriRequest(Request request, Request.Options options)
      throws URISyntaxException {
    RequestBuilder requestBuilder = RequestBuilder.create(request.httpMethod().name());

    // per request timeouts
    RequestConfig requestConfig =
        (client instanceof Configurable
                ? RequestConfig.copy(((Configurable) client).getConfig())
                : RequestConfig.custom())
            .setConnectTimeout(options.connectTimeoutMillis())
            .setSocketTimeout(options.readTimeoutMillis())
            .setRedirectsEnabled(options.isFollowRedirects())
            .build();

View on GitHub (pinned to e2a1e27560)