apple/pkl · error · URISyntaxException

invalidOpaqueFileUri

invalidOpaqueFileUri

Error message

File URIs must have a path that starts with `/` (e.g. file:/path/to/my_module.pkl).

What it means

validateFileUri rejects file: URIs whose scheme-specific part does not start with '/' (opaque file URIs like file:foo.pkl). Pkl requires hierarchical file URIs with an absolute path so they can be converted to filesystem paths deterministically.

Solutions

  1. Build file URIs from absolute paths, e.g. new File(path).toURI() or Paths.get(p).toUri()
  2. Prefix the path with '/' when constructing the URI manually: file:/path/to/my_module.pkl
  3. Resolve the URI against a base directory before validation

Example fix

// before
URI uri = URI.create("file:my_module.pkl");
// after
URI uri = java.nio.file.Paths.get("my_module.pkl").toAbsolutePath().toUri();
Defensive patterns

Strategy: validation

Validate before calling

if (uri.getScheme().equals("file") && !uri.getSchemeSpecificPart().startsWith("/")) throw new IllegalArgumentException("file URI must have absolute path");

Type guard

function isValidFileUri(u) { return u.getScheme().equals("file") && u.getSchemeSpecificPart().startsWith("/"); }

Try / catch

try { IoUtils.validateFileUri(uri) } catch (URISyntaxException e) { /* convert via Paths.get(...).toUri() and retry */ }

Prevention

When it happens

Trigger: Calling IoUtils.validateFileUri with URI.create("file:my_module.pkl") or any file URI built without a leading slash in its path.

Common situations: Hand-constructing file URIs by string concatenation without encoding an absolute path, or reading a file URI from user config written in opaque form.

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 apple/pkl@f3efcbfc9b (2026-09-08). Data as JSON: /api/errors/f860c10b3bf64959. Report an issue: GitHub.

Appendix: source

Thrown at pkl-core/src/main/java/org/pkl/core/util/IoUtils.java:893

  /** Returns a path string that uses unix-like path separators. */
  public static String toNormalizedPathString(Path path) {
    if (isWindows()) {
      return path.toString().replace("\\", "/");
    }
    return path.toString();
  }

  private static int getExclamationMarkIndex(String jarUri) {
    var index = jarUri.indexOf('!');
    if (index == -1) {
      throw new IllegalArgumentException("Invalid `jar:` URI (missing `!`): " + jarUri);
    }
    return index;
  }

  public static void validateFileUri(URI uri) throws URISyntaxException {
    if (!uri.getSchemeSpecificPart().startsWith("/")) {
      throw new URISyntaxException(uri.toString(), ErrorMessages.create("invalidOpaqueFileUri"));
    }
  }

  public static void validateRewriteRule(URI rewrite) {
    if (!Objects.equals(rewrite.getScheme(), "http")
        && !Objects.equals(rewrite.getScheme(), "https")) {
      throw new IllegalArgumentException(
          "Rewrite rule must start with 'http://' or 'https://', but was '%s'".formatted(rewrite));
    }

    if (!rewrite.toString().endsWith("/")) {
      throw new IllegalArgumentException(
          "Rewrite rule must end with '/', but was '%s'".formatted(rewrite));
    }
  }

  private static boolean isReservedHeaderName(String headerName) {
    var normalizedHeader = headerName.toLowerCase(Locale.ROOT);

View on GitHub (pinned to f3efcbfc9b)