oracle/graal · error · IllegalArgumentException
LogFile substitution %s cannot be combined with any other ch
Error message
LogFile substitution %s cannot be combined with any other characters
What it means
GraalVM throws IllegalArgumentException from HotSpotTTYStreamProvider when the -Dgraal.LogFile value uses the %o (stdout) or %e (stderr) substitution combined with any other characters. These two substitutions must constitute the entire LogFile value because they redirect compiler log output wholesale to an existing stream rather than to a file path. Any prefix/suffix (e.g. 'graal_%o.log') makes the resulting name meaningless, so the provider rejects it up front.
Source
Thrown at compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/HotSpotTTYStreamProvider.java:142
*/
private static String makeFilename(String nameTemplate) {
String name = nameTemplate;
if (name.contains("%p")) {
name = name.replace("%p", GraalServices.getExecutionID());
}
if (name.contains("%i")) {
name = name.replace("%i", IsolateUtil.getIsolateID(false));
}
if (name.contains("%I")) {
name = name.replace("%I", IsolateUtil.getIsolateID(true));
}
if (name.contains("%t")) {
name = name.replace("%t", String.valueOf(GraalServices.milliTimeStamp()));
}
for (String subst : new String[]{"%o", "%e"}) {
if (name.contains(subst) && !name.equals(subst)) {
throw new IllegalArgumentException("LogFile substitution " + subst + " cannot be combined with any other characters");
}
}
return name;
}
/**
* An output stream that redirects to {@link HotSpotJVMCIRuntime#getLogStream()}. The
* {@link HotSpotJVMCIRuntime#getLogStream()} value is only accessed the first time an IO
* operation is performed on the stream. This is required to break a deadlock in early JVMCI
* initialization.
*/
class DelayedOutputStream extends OutputStream {
private volatile OutputStream lazy;
private OutputStream lazy() {
if (lazy == null) {
synchronized (this) {View on GitHub (pinned to a66e9ccd1d)
Solutions
- Use %o or %e alone: -Dgraal.LogFile=%o (or %e) with no other characters.
- If you need generated file names, use the embeddable substitutions instead: %i/%I (isolate id) or %t (timestamp), e.g. -Dgraal.LogFile='graal_%i.log'.
- If you need a literal percent-containing name, pick a name without %o/%e substrings.
Example fix
# before -Dgraal.LogFile=graal_%o.log # after (redirect to stdout wholesale) -Dgraal.LogFile=%o # or, generated file name -Dgraal.LogFile=graal_%i.log
Defensive patterns
Strategy: validation
Validate before calling
// Java: validate the LogFile value before enabling compiler logging
String logFile = System.getProperty("graal.LogFile", "");
for (String wholeOnly : new String[]{"%o", "%e"}) {
if (logFile.contains(wholeOnly) && !logFile.equals(wholeOnly)) {
throw new IllegalArgumentException(
"graal.LogFile: " + wholeOnly + " must be the entire value, got: " + logFile);
}
} Try / catch
try {
HotSpotTTYStreamProvider.openLogStream(); // or launch JVM with graal.LogFile
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("cannot be combined")) { /* fix the property, retry */ }
throw e;
} Prevention
- In launch scripts, generate -Dgraal.LogFile from a template that only embeds %i, %I or %t.
- Add a startup assertion that %o/%e, when present, equal the whole property value.
When it happens
Trigger: Setting -Dgraal.LogFile=%o or -Dgraal.LogFile=%e together with extra text, e.g. -Dgraal.BenchmarkCounters... plus -Dgraal.LogFile='log_%o'. Only the substitutions %i, %I and %t may be embedded in a larger file name; %o and %e are whole-value-only.
Common situations: A developer wants compiler logs tagged per isolate or timestamp but mistakenly uses %o/%e as a name fragment; or copy-pastes a LogFile pattern from a script that appends a suffix. Common in benchmarking setups where each run writes 'graal_<n>.log' and someone swaps in %o expecting stream capture.
Related errors
- too many counters, reduce number of counters or increase -XX
- Set the JVMCI_VERSION_CHECK environment variable to "ignore"
- Unknown argument: %s
- Unexpected OS name: %s
- Profile file for path %s exists already
AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14).
Data as JSON: /api/errors/6acb9a53c190094b.
Report an issue: GitHub.