grpc/grpc-java · error · IllegalArgumentException

Missing required scheme.

Error message

Missing required scheme.

What it means

Uri.create() implements RFC 3986 parsing and requires every absolute URI to begin with a scheme followed by ':'. If scanning the string finds no ':' before the first '/', '?' or '#' (schemeColon < 0), it throws IllegalArgumentException "Missing required scheme." — unlike java.net.URI, grpc's Uri does not accept scheme-less URI references.

Source

Thrown at api/src/main/java/io/grpc/Uri.java:231

   */
  public static Uri create(String s) {
    Builder builder = new Builder();
    int i = 0;
    final int n = s.length();

    // 3.1. Scheme: Look for a ':' before '/', '?', or '#'.
    int schemeColon = -1;
    for (; i < n; ++i) {
      char c = s.charAt(i);
      if (c == ':') {
        schemeColon = i;
        break;
      } else if (c == '/' || c == '?' || c == '#') {
        break;
      }
    }
    if (schemeColon < 0) {
      throw new IllegalArgumentException("Missing required scheme.");
    }
    builder.setRawScheme(s.substring(0, schemeColon));

    // 3.2. Authority. Look for '//' then keep scanning until '/', '?', or '#'.
    i = schemeColon + 1;
    if (i + 1 < n && s.charAt(i) == '/' && s.charAt(i + 1) == '/') {
      // "//" just means we have an authority. Skip over it.
      i += 2;

      int authorityStart = i;
      for (; i < n; ++i) {
        char c = s.charAt(i);
        if (c == '/' || c == '?' || c == '#') {
          break;
        }
      }
      builder.setRawAuthority(s.substring(authorityStart, i));
    }

View on GitHub (pinned to 64daddc1f3)

Solutions

  1. Prepend an explicit scheme to the string (e.g. "https://" or the appropriate scheme) before parsing
  2. If the string is a host:port, wrap it in the desired scheme form before passing to Uri.create()
  3. Use Uri.parse() and catch the error to give users a clearer validation message
  4. Validate config values at startup to require an absolute URI

Example fix

// before
Uri.create("example.com/api"); // throws: no scheme
// after
Uri.create("https://example.com/api");
Defensive patterns

Strategy: validation

Validate before calling

if (!target.matches("[A-Za-z][A-Za-z0-9+.-]*:.*")) throw new IllegalArgumentException("Target requires a scheme: " + target);

Try / catch

try {
  uri = Uri.create(target);
} catch (IllegalArgumentException e) {
  throw new InvalidEndpointException("Target missing scheme: " + target, e);
}

Prevention

When it happens

Trigger: Passing a URI string with no scheme: "localhost:50051" without prefix is fine, but "//host/x", "host/path", or a bare target like "dns:///..." is fine too — the failing case is strings like "example.com/foo" or "#frag" where no colon appears before the first '/', '?', or '#'.

Common situations: gRPC target strings like "localhost:50051" are OK (scheme='localhost') but strings such as "my-service.my-ns:50051" typed without scheme in configs; ODBC-style or browser-style relative URLs reused as gRPC targets; stripping the scheme manually before calling create().

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 grpc/grpc-java@64daddc1f3 (2026-09-08). Data as JSON: /api/errors/73e06d5041e7a8b3. Report an issue: GitHub.