apple/pkl · error · IOException

Is a directory

Error message

Is a directory

What it means

The message 'Is a directory' is produced by ResolvedModuleKeys.loadSource (LocalPathModuleKey) when reading a module resolves to a directory rather than a file. On Windows, reading a directory throws AccessDeniedException, so the code checks Files.isDirectory(path) and rethrows a uniform IOException('Is a directory') to sync the error message across operating systems. This indicates a module URI/path pointed at a directory instead of a file.

Source

Thrown at pkl-core/src/main/java/org/pkl/core/module/ResolvedModuleKeys.java:111

    @Override
    public URI getUri() {
      return uri;
    }

    @Override
    public String loadSource() throws IOException {
      try {
        if (nofollow) {
          try (var in = Files.newInputStream(path, LinkOption.NOFOLLOW_LINKS)) {
            return new String(in.readAllBytes(), StandardCharsets.UTF_8);
          }
        }
        return Files.readString(path, StandardCharsets.UTF_8);
      } catch (AccessDeniedException e) {
        // Windows throws `AccessDeniedException` when reading directories.
        // Sync error between different OSes.
        if (Files.isDirectory(path)) {
          throw new IOException("Is a directory");
        }
        throw e;
      }
    }
  }

  private static class Url implements ResolvedModuleKey {
    final ModuleKey original;
    final URI uri;
    final URL url;

    Url(ModuleKey original, URI uri, URL url) {
      this.original = original;
      this.uri = uri;
      this.url = url;
    }

    @Override

View on GitHub (pinned to f3efcbfc9b)

Solutions

  1. Point the import/path at the actual .pkl file, e.g. `import "dir/module.pkl"` instead of `import "dir"`.
  2. Verify with `ls`/`Get-Item` that the resolved path is a regular file, not a directory.
  3. If a symlink is involved, retarget it to a file.
  4. Fix any tooling or templating that generated the truncated path.

Example fix

// before
import "file:///home/me/project/shared"
// after
import "file:///home/me/project/shared/config.pkl"
Defensive patterns

Strategy: validation

Validate before calling

import java.nio.file.*;
Path p = Path.of("/home/me/project/shared");
if (!Files.isRegularFile(p)) throw new IllegalArgumentException("Module path must be a file, got: " + (Files.isDirectory(p) ? "directory" : p));

Prevention

When it happens

Trigger: Calling loadSource on a local-path module key whose path is a directory — e.g. an import pointing at a folder (`import "file:///some/dir"`) or ProjectDepsManager loading a deps URI that resolves to a directory.

Common situations: Typing an import path without the filename (expecting index.pkl resolution that isn't supported); a path truncated mid-edit; symlinked or mount-point directories mistaken for files; a deps file placeholder directory in CI.

Related errors


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