{"record":{"id":"1bd2e302b492c73f","repo":"grpc/grpc-java","slug":"has-authority-non-empty-path-must-start-with","errorCode":null,"errorMessage":"Has authority -- Non-empty path must start with '/'","messagePattern":"Has authority -- Non-empty path must start with '/'","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"api/src/main/java/io/grpc/Uri.java","lineNumber":185,"sourceCode":"  @Nullable private final String host;\n  @Nullable private final String port;\n  private final String path; // In RFC 3986, path is always defined (but can be empty).\n  @Nullable private final String query;\n  @Nullable private final String fragment;\n\n  private Uri(Builder builder) {\n    this.scheme = checkNotNull(builder.scheme, \"scheme\");\n    this.userInfo = builder.userInfo;\n    this.host = builder.host;\n    this.port = builder.port;\n    this.path = builder.path;\n    this.query = builder.query;\n    this.fragment = builder.fragment;\n\n    // Checks common to the parse() and Builder code paths.\n    if (hasAuthority()) {\n      if (!path.isEmpty() && !path.startsWith(\"/\")) {\n        throw new IllegalArgumentException(\"Has authority -- Non-empty path must start with '/'\");\n      }\n    } else {\n      if (path.startsWith(\"//\")) {\n        throw new IllegalArgumentException(\"No authority -- Path cannot start with '//'\");\n      }\n    }\n  }\n\n  /**\n   * Parses a URI from its string form.\n   *\n   * @throws URISyntaxException if 's' is not a valid RFC 3986 URI.\n   */\n  public static Uri parse(String s) throws URISyntaxException {\n    try {\n      return create(s);\n    } catch (IllegalArgumentException e) {\n      throw new URISyntaxException(s, e.getMessage());","sourceCodeStart":167,"sourceCodeEnd":203,"githubUrl":"https://github.com/grpc/grpc-java/blob/64daddc1f3d1975670f769f3e97bde8b2ba32d25/api/src/main/java/io/grpc/Uri.java#L167-L203","documentation":"Uri's constructor validates RFC 3986 path/authority relationships. When the URI has an authority component, any non-empty path must start with '/'. Otherwise an IllegalArgumentException is thrown. This guards the invariant that hierarchical paths after an authority are root-relative.","triggerScenarios":"Building a Uri with setAuthority(...) and then setPath(\"foo\") (no leading slash), or parsing a string like \"scheme://hostfoo\" where the path portion is non-empty and lacks a leading '/'.","commonSituations":"Hand-assembling target/authority strings for gRPC channels (e.g. authority \"host:8080\" plus a path missing its slash); mis-parsing URIs where the authority and path were split incorrectly; constructing links from concatenated strings.","solutions":["Prefix the path with '/' when an authority is present and the path is non-empty","If no path is desired, pass the empty string instead of a slash-less segment","Recheck how the URI string is split into authority and path; use Uri.parse() rather than manual string slicing"],"exampleFix":"// before\nUri.newBuilder().setScheme(\"https\").setHost(\"example.com\").setPath(\"api\") // throws\n// after\nUri.newBuilder().setScheme(\"https\").setHost(\"example.com\").setPath(\"/api\").build();","handlingStrategy":"validation","validationCode":"if (hasAuthority && !path.isEmpty() && !path.startsWith(\"/\")) path = \"/\" + path;","typeGuard":null,"tryCatchPattern":"try {\n  uri = builder.build();\n} catch (IllegalArgumentException e) {\n  throw new IllegalArgumentException(\"Malformed URI: \" + e.getMessage(), e);\n}","preventionTips":["When an authority is set, always make paths absolute (leading '/')","Use Uri.parse() on full strings instead of assembling builder fields from raw slices","Add unit tests for authority+path combinations"],"tags":["uri","rfc3986","validation"],"backgroundTag":"invalid-url-format","analyzedSha":"64daddc1f3d1975670f769f3e97bde8b2ba32d25","analyzedAt":"2026-09-08T06:14:57.704Z","contentChangedAt":"2026-09-08T06:14:57.704Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}