apple/pkl · error · ExecutorException
I/O error loading Pkl module `%s`.
Error message
I/O error loading Pkl module `%s`.
What it means
detectRequestedPklVersion reads the module file as UTF-8 to extract its @ModuleInfo minPklVersion. If Files.readString throws IOException, evaluatePath aborts with ExecutorException "I/O error loading Pkl module". The original IOException is attached as the cause.
Source
Thrown at pkl-executor/src/main/java/org/pkl/executor/EmbeddedExecutor.java:113
@Nullable Version requestedVersion,
@Nullable PklDistribution distribution,
long startTime,
long endTime) {
logger.info(
"Finished evaluating Pkl module. modulePath={} outcome={} requestedVersion={} selectedVersion={} elapsedMillis={}",
modulePath,
success,
requestedVersion == null ? "n/a" : requestedVersion.toString(),
distribution == null ? "n/a" : distribution.getVersion().toString(),
(endTime - startTime) / 1_000_000);
}
private Version detectRequestedPklVersion(Path modulePath, ExecutorOptions options) {
String sourceText;
try {
sourceText = Files.readString(modulePath, StandardCharsets.UTF_8);
} catch (IOException e) {
throw new ExecutorException(
String.format("I/O error loading Pkl module `%s`.", toDisplayPath(modulePath, options)),
e);
}
var version = extractMinPklVersion(sourceText);
if (version != null) return version;
var availableVersions =
pklDistributions.stream()
.map(it -> it.getVersion().toString())
.collect(Collectors.joining(", "));
throw new ExecutorException(
String.format(
"Pkl module `%s` does not state which Pkl version it requires. (Available versions: %s)%n"
+ "To fix this problem, annotate the module's `amends`, `extends`, or `module` clause with `@ModuleInfo { minPklVersion = \"x.y.z\" }`.",
toDisplayPath(modulePath, options), availableVersions));
}View on GitHub (pinned to f3efcbfc9b)
Solutions
- Check file read permissions for the process user (chmod / run as the right user)
- Confirm the file still exists and is on a healthy filesystem at read time
- Retry on transient I/O errors if the file is on a network mount
- Inspect the cause (getCause()) for the underlying IOException detail
Example fix
// before
executor.evaluatePath(path, options); // may throw opaque IO error
// after
if (!Files.isReadable(path)) throw new IllegalStateException("not readable: " + path);
try { executor.evaluatePath(path, options); }
catch (ExecutorException e) { log.error("module load failed", e.getCause()); throw e; } Defensive patterns
Strategy: try-catch
Validate before calling
if (!Files.isReadable(path)) throw new IllegalStateException("module not readable: " + path);
Type guard
boolean isReadableFile(Path p) { return Files.isRegularFile(p) && Files.isReadable(p); }
Try / catch
try { executor.evaluatePath(p, options); } catch (ExecutorException e) { if (e.getCause() instanceof IOException io) throw new ModuleLoadException(p, io); throw e; }
Prevention
- Ensure the executor process user has read permission
- Retry transient IO failures on network filesystems
- Verify UTF-8 encoding of modules
- Keep modules on local, healthy storage for evaluation
When it happens
Trigger: The file existed at the existence check but could not be read as UTF-8 text: permission denied, file deleted between checks (race), I/O error on a network/NFS mount, or encoding issues surfaced as an IO failure.
Common situations: Files readable to one user but not the executor's user; modules on removable/network drives; TOCTOU races where the file is removed between the isRegularFile check and readString.
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
- cannotLoadProjectDepsJson
- ioErrorWritingTestOutputFile
- ioErrorReadingTestOutputFile
- ioErrorLoadingModule
- ioErrorLoadingModule
AI-assisted analysis of apple/pkl@f3efcbfc9b (2026-09-08).
Data as JSON: /api/errors/2ad0b2354b1daae5.
Report an issue: GitHub.