oracle/graal · error · IllegalArgumentException
Cannot use the specified log.file
Error message
Cannot use the specified log.file
What it means
Thrown when the 'log.file' VM option is processed: Espresso tries to open the given path with Files.newOutputStream(WRITE, CREATE, APPEND) and the IOException is wrapped in IllegalArgumentException('Cannot use the specified log.file'). The stream becomes the engine's log handler, so it must be openable at build time.
Source
Thrown at espresso-compiler-stub/src/com.oracle.truffle.espresso.vmaccess/src/com/oracle/truffle/espresso/vmaccess/EspressoExternalVMAccessBuilder.java:207
String group = key;
if (index >= 0) {
group = group.substring(0, index);
}
if ("log".equals(group)) {
if (key.endsWith(".level")) {
try {
Level.parse(value);
builder.option(key, value);
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException(String.format("Invalid log level %s specified. %s'", vmOption, e.getMessage()));
}
return;
} else if ("log.file".equals(key)) {
OutputStream out;
try {
out = new BufferedOutputStream(Files.newOutputStream(Paths.get(value), StandardOpenOption.WRITE, StandardOpenOption.CREATE, StandardOpenOption.APPEND));
} catch (IOException e) {
throw new IllegalArgumentException("Cannot use the specified log.file", e);
}
builder.logHandler(out);
return;
}
}
OptionDescriptor descriptor = findOptionDescriptor(group, key);
if (descriptor == null) {
key = JAVA_LANGUAGE_ID + "." + key;
descriptor = findOptionDescriptor(JAVA_LANGUAGE_ID, key);
if (descriptor == null) {
throw new IllegalArgumentException("Unrecognized VM option: '" + vmOption);
}
}
try {
descriptor.getKey().getType().convert(value);
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException(String.format("Invalid VM option %s specified. %s", vmOption, e.getMessage()));
}View on GitHub (pinned to a66e9ccd1d)
Solutions
- Pre-create the parent directory and verify writability of the exact resolved path before building the VMAccess
- Use an absolute path for log.file so it does not depend on the process working directory
- Check filesystem permissions/mount flags (read-only container volumes) and pick a writable location such as the temp dir
Example fix
// before
builder.option("java.log.file", "logs/espresso.log"); // 'logs/' may not exist
// after
Path logPath = Path.of("/var/myapp/log/espresso.log").toAbsolutePath();
Files.createDirectories(logPath.getParent());
builder.option("java.log.file", logPath.toString()); Defensive patterns
Strategy: try-catch
Validate before calling
Path p = Path.of(logFile).toAbsolutePath();
Files.createDirectories(p.getParent());
if (!Files.isWritable(p.getParent())) throw new IOException("log dir not writable: " + p.getParent()); Try / catch
catch (IllegalArgumentException e) when message contains 'log.file': report the resolved absolute path and permissions, suggest a writable directory
Prevention
- Use absolute log paths so behavior does not depend on process cwd
- Pre-create the log directory at deployment time and verify writability in startup checks
- In containers, mount a writable volume for logs
When it happens
Trigger: Setting a 'java.log.file=<path>' option where the path cannot be opened for append: nonexistent parent directory, no write permission, path is a directory, read-only filesystem, or invalid path syntax on the platform.
Common situations: Relative log paths resolved against an unexpected working directory (service/daemon cwd); container or read-only mount without a writable /var/log; SELinux/AppArmor denying writes; path with spaces or special characters not properly escaped in the option string.
Related errors
- Failed to print the optimization log to a file: %s
- Could not read the files of the experiment {experimentId}: {
- Invalid log level %s specified. %s'
- LogFile substitution %s cannot be combined with any other ch
- Invalid directed inlining rules file path: {path}
AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14).
Data as JSON: /api/errors/747d8c5d136342ab.
Report an issue: GitHub.