apple/pkl · error · IllegalArgumentException

Invalid `jar:` URI (missing `!`):

Error message

Invalid `jar:` URI (missing `!`): 

What it means

Helper getExclamationMarkIndex parses jar: URIs of the form jar:<inner-uri>!/entry. It throws IllegalArgumentException when the string contains no '!' separator, meaning no nested entry is specified, which Pkl cannot treat as a valid jar URI.

Solutions

  1. Append the '!/<entry>' suffix naming the resource inside the jar
  2. Strip the 'jar:' scheme first if you meant to handle the inner URI instead
  3. Check with indexOf('!') before invoking the jar-parsing helper

Example fix

// before
String inner = IoUtils.extractJarPath("file:/lib/app.jar");
// after
String inner = IoUtils.extractJarPath("jar:file:/lib/app.jar!/resources/module.pkl");
Defensive patterns

Strategy: validation

Validate before calling

if (!jarUri.startsWith("jar:") || !jarUri.contains("!")) throw new IllegalArgumentException("expected jar:<uri>!/<entry>");

Type guard

function isJarEntryUri(s) { return /^jar:.+!\/.+/.test(s); }

Try / catch

try { parseJarUri(jarUri) } catch (IllegalArgumentException e) { /* fall back to treating as plain file */ }

Prevention

When it happens

Trigger: Calling IoUtils jar-URI utilities (extracting the inner URI or entry path) with a string like 'file:/lib.jar' that lacks the '!/path' suffix.

Common situations: Passing a plain JAR file path or inner URI to code expecting jar:<base>!<entry>, e.g. when resolving resources inside jars on the classpath.

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/292e5b3aea9f415a. Report an issue: GitHub.

Appendix: source

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

      } else {
        sb.append(character);
      }
    }
    return sb.toString();
  }

  /** 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("/")) {

View on GitHub (pinned to f3efcbfc9b)