apple/pkl · error · InvalidUserDataException

Failed to parse Pkl module file path

Error message

Failed to parse Pkl module file path: ${s}

What it means

parseModuleNotation accepts a String notation for a Pkl module. If the string is not a valid URI it falls back to interpreting it as a filesystem path; when Paths.get(s) throws InvalidPathException or UnsupportedOperationException, the library wraps it in this InvalidUserDataException so Gradle reports which notation string could not be parsed.

Solutions

  1. Fix the notation string so it is either a valid module URI (e.g. pkl:, https:, file:) or a valid filesystem path for the OS
  2. Use a java.io.File or FileSystemLocation (project.layout.files/projectDir.resolve(...)) notation instead of a raw String
  3. Check the string for illegal characters (NUL bytes, invalid separators) before passing it
  4. Print/log the offending notation (it is included in the message) and correct it in build scripts or task inputs

Example fix

// before
pklModules = listOf("pkl:base?\u0000")
// after
pklModules = listOf("pkl:base")
Defensive patterns

Strategy: validation

Validate before calling

// Java/Gradle
static boolean isValidNotation(String s) {
  try { java.nio.file.Paths.get(s); return true; }
  catch (java.nio.file.InvalidPathException | UnsupportedOperationException e) { return false; }
}
// call before assigning: if (!isValidNotation(notation)) throw new IllegalArgumentException(...);

Type guard

static boolean isSafeModuleNotation(Object n) {
  return n instanceof String s && isValidNotation(s) || n instanceof java.io.File || n instanceof org.gradle.api.file.FileSystemLocation;
}

Try / catch

try {
  file = PluginUtils.parseModuleNotation(notation);
} catch (InvalidUserDataException e) {
  logger.error("Bad Pkl module notation: {}", e.getMessage());
  throw new GradleException("Fix module notation: " + notation, e);
}

Prevention

When it happens

Trigger: Passing a String to a Pkl Gradle plugin module property (e.g. pkl project/module configuration) that contains characters illegal in a filesystem path, such as a NUL byte, or a URI-formatted string on a platform whose Path implementation rejects it (UnsupportedOperationException from Paths.get).

Common situations: Typos or unescaped characters in pklModulePath/pklModule URIs, copy-pasting a URI into a field expected to be a path, Windows path handling with unusual characters, or generating notation strings programmatically with embedded nulls.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of apple/pkl@f3efcbfc9b (2026-09-08). Data as JSON: /api/errors/b49bf707c584a5ce. Report an issue: GitHub.

Appendix: source

Thrown at pkl-gradle/src/main/java/org/pkl/gradle/utils/PluginUtils.java:103

    } else if (notation instanceof URL url) {
      try {
        return parseModuleNotation(url.toURI());
      } catch (URISyntaxException e) {
        throw new InvalidUserDataException("Failed to parse Pkl module URI: " + notation, e);
      }
    } else if (notation instanceof CharSequence) {
      var s = notation.toString();
      if (IoUtils.isUriLike(s)) {
        try {
          return parseModuleNotation(IoUtils.toUri(s));
        } catch (URISyntaxException e) {
          throw new InvalidUserDataException("Failed to parse Pkl module URI: " + s, e);
        }
      } else {
        try {
          return Paths.get(s).toFile();
        } catch (InvalidPathException | UnsupportedOperationException e) {
          throw new InvalidUserDataException("Failed to parse Pkl module file path: " + s, e);
        }
      }
    } else if (notation instanceof FileSystemLocation location) {
      return location.getAsFile();
    } else {
      throw new InvalidUserDataException(
          "Unsupported value of type "
              + notation.getClass()
              + " used as a module path: "
              + notation);
    }
  }

  /**
   * Converts either a file or a URI to a URI. We convert a relative file to a URI via the {@link
   * IoUtils#createUri(String)} because other ways of conversion can make relative paths into
   * absolute URIs, which may break module loading.
   */

View on GitHub (pinned to f3efcbfc9b)