apple/pkl · error · VmException

ioErrorLoadingModule

ioErrorLoadingModule

Error message

ioErrorLoadingModule

What it means

ioErrorLoadingModule is an evaluation error thrown when the Pkl evaluator fails to read a module's source over I/O during module source normalization (EvaluatorImpl.normalizeModuleSource). The module URI is included in the error so the developer knows which resource could not be loaded. It wraps an IOException encountered while resolving/reading the module (e.g. from a file, HTTP, or package-backed module source).

Source

Thrown at pkl-core/src/main/java/org/pkl/core/EvaluatorImpl.java:457

  private ModuleSource normalizeModuleSource(ModuleSource moduleSource) {
    if (moduleSource.getContents() != null
        || moduleSource.getUri().isAbsolute()
        || !moduleSource.getUri().getPath().startsWith("@")) {
      return moduleSource;
    }
    try {
      if (projectFileUri != null) {
        var moduleKey = moduleResolver.resolve(projectFileUri);
        var uri = IoUtils.resolve(securityManager, moduleKey, moduleSource.getUri());
        return ModuleSource.uri(uri);
      } else {
        throw new PackageLoadError("cannotResolveDependencyNoProject");
      }
    } catch (URISyntaxException e) {
      // impossible condition
      throw PklBugException.unreachableCode();
    } catch (IOException e) {
      throw new VmExceptionBuilder()
          .evalError("ioErrorLoadingModule", moduleSource.getUri())
          .build();
    } catch (ExternalReaderProcessException | SecurityManagerException | PackageLoadError e) {
      throw new VmExceptionBuilder().withCause(e).build();
    }
  }

  private <T> T doEvaluate(ModuleSource moduleSource, Function<VmTyped, T> doEvaluate) {
    return doEvaluate(
        () -> {
          var moduleKey = moduleResolver.resolve(normalizeModuleSource(moduleSource));
          var module = VmLanguage.get(null).loadModule(moduleKey);
          return doEvaluate.apply(module);
        });
  }

  private void handleTimeout(@Nullable TimeoutTask timeoutTask) {
    if (timeoutTask == null || timeoutTask.cancel()) return;

View on GitHub (pinned to f3efcbfc9b)

Solutions

  1. Verify the module URI exists and is readable (ls/check permissions, curl for remote URIs).
  2. Use an absolute or correctly project-rooted path; relative module paths resolve against the importing module or base URI.
  3. For remote modules, check network/proxy connectivity and retry.
  4. Catch PklException/VmException with this error code and surface a clear message naming the module URI.

Example fix

// before
evaluator.evaluate(OutputFormat.text(), Paths.get("config/pkls/Main.pkl"));
// after
Path p = Paths.get("config/pkls/Main.pkl");
if (!Files.isReadable(p)) throw new IllegalArgumentException("Module not readable: " + p);
evaluator.evaluate(OutputFormat.text(), p);
Defensive patterns

Strategy: validation

Validate before calling

Path p = Paths.get("config/Main.pkl");
if (!Files.isRegularFile(p) || !Files.isReadable(p)) {
  throw new IllegalStateException("Module unreadable: " + p.toAbsolutePath());
}

Type guard

static boolean isLoadableModule(URI uri) {
  try {
    if ("file".equals(uri.getScheme())) return Files.isReadable(Paths.get(uri));
    return uri.toURL().openConnection().getInputStream() != null; // remote probe
  } catch (IOException e) { return false; }
}

Try / catch

try {
  evaluator.evaluateOutputText(source);
} catch (PklException e) {
  if (e.getMessage().contains("ioErrorLoadingModule")) {
    throw new IOException("Cannot load module: " + e.getMessage(), e);
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling EvaluatorImpl to evaluate a module whose source cannot be read: a file:// module path that no longer exists or is unreadable, an https:// module whose fetch fails, or a package dependency module whose cached/remote content cannot be read. normalizeModuleSource catches IOException and rethrows as VmException with code ioErrorLoadingModule.

Common situations: Typo in the module path passed to evaluate(); reading a Pkl file deleted or moved after the URI was computed; network outage or proxy blocking a remote module; filesystem permission changes; container images missing files bundled at build time.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


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