{"record":{"id":"1d737b1671dbab96","repo":"apple/pkl","slug":"unsupported-protocol","errorCode":null,"errorMessage":"Unsupported protocol: ","messagePattern":"Unsupported protocol: ","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"pkl-core/src/main/java/org/pkl/core/util/IoUtils.java","lineNumber":97,"sourceCode":"    \"upgrade\",\n    \"te\",\n    \"transfer-encoding\",\n    \"trailer\"\n  };\n\n  // keep in sync with stdlib `EvaluatorSettings.reservedHttpHeaderPrefix`\n  private static final String[] reservedHeaderPrefixes = {\"proxy-\", \"sec-\"};\n\n  private IoUtils() {}\n\n  public static URL toUrl(URI uri) throws IOException {\n    try {\n      return uri.toURL();\n    } catch (Error e) {\n      // best we can do for now\n      // rely on caller to provide context, e.g., the requested module URI\n      if (e.getClass().getName().equals(\"com.oracle.svm.core.jdk.UnsupportedFeatureError\")) {\n        throw new IOException(\"Unsupported protocol: \" + uri.getScheme());\n      }\n\n      throw e;\n    }\n  }\n\n  /** Checks whether the given string is \"URI-like\", i.e. matches a pattern like {@code foo:bar}. */\n  public static boolean isUriLike(String str) {\n    return uriLike.matcher(str).matches();\n  }\n\n  public static boolean isWindowsAbsolutePath(String str) {\n    return windowsDriveLetterLike.matcher(str).matches();\n  }\n\n  /**\n   * Converts the given string to a {@link URI}. This method MUST be used for constructing module\n   * and resource URIs. Unlike {@code new URI(str)}, it correctly escapes paths of relative URIs.","sourceCodeStart":79,"sourceCodeEnd":115,"githubUrl":"https://github.com/apple/pkl/blob/f3efcbfc9b60d30053b0536d664948d7aa1b8673/pkl-core/src/main/java/org/pkl/core/util/IoUtils.java#L79-L115","documentation":"IoUtils.toUrl converts a URI to a java.net.URL; on GraalVM native-image, URI schemes without a registered protocol handler throw UnsupportedFeatureError at runtime. toUrl catches that specific error and rethrows an IOException \"Unsupported protocol: <scheme>\", leaving context-giving to the caller, since the scheme has no URL stream handler available in the native binary.","triggerScenarios":"Calling IoUtils.toUrl with a URI whose scheme has no java.net.URL protocol handler in the current runtime — e.g. a custom scheme (\"project:\", \"module:\", \"pkg:\") on GraalVM native-image, or genuinely unhandled schemes.","commonSituations":"Running Pkl as a native image where only file/http(s)/jar handlers are registered but code attempts to open a custom-scheme URI as a URL; typo'd schemes; or code bypassing the proper scheme-specific reader.","solutions":["Use a scheme with a registered handler (file:, http:, https:) for the actual fetch","Route custom-scheme URIs through their proper reader/resolver instead of toUrl/URL.openStream","Check the scheme spelling in the URI","If embedding Pkl native-image, register a protocol handler for the custom scheme"],"exampleFix":"// before\nURL url = IoUtils.toUrl(URI.create(\"projectpartial:foo\"));\n// after\nURL url = IoUtils.toUrl(URI.create(\"file:///path/to/project/foo\"));","handlingStrategy":"try-catch","validationCode":"const SUPPORTED = ['http', 'https', 'file', 'jar'];\nconst hasSupportedProtocol = (uri) => SUPPORTED.includes((uri.match(/^([a-z][a-z0-9+.-]*):/) || [])[1] || '');","typeGuard":"const isSupportedUrl = (uri) => /^(https?|file|jar):/.test(uri);","tryCatchPattern":"try {\n  URL url = IoUtils.toUrl(uri);\n} catch (IOException e) {\n  if (e.getMessage().startsWith(\"Unsupported protocol:\")) {\n    // resolve via the scheme-specific reader instead of URL.openStream\n  } else throw e;\n}","preventionTips":["Only call toUrl with file/http/https/jar URIs","Route custom-scheme URIs through their dedicated reader/resolver","If on GraalVM native-image, remember protocol handlers beyond the defaults are not registered","Validate scheme spelling before conversion"],"tags":["uri","protocol","graalvm","native-image"],"backgroundTag":"unsupported-protocol","analyzedSha":"f3efcbfc9b60d30053b0536d664948d7aa1b8673","analyzedAt":"2026-09-08T13:10:45.570Z","contentChangedAt":"2026-09-08T13:10:45.570Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}