{"record":{"id":"6acb9a53c190094b","repo":"oracle/graal","slug":"logfile-substitution-s-cannot-be-combined-with-an","errorCode":null,"errorMessage":"LogFile substitution %s cannot be combined with any other characters","messagePattern":"LogFile substitution (.+?) cannot be combined with any other characters","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/HotSpotTTYStreamProvider.java","lineNumber":142,"sourceCode":"         */\n        private static String makeFilename(String nameTemplate) {\n            String name = nameTemplate;\n            if (name.contains(\"%p\")) {\n                name = name.replace(\"%p\", GraalServices.getExecutionID());\n            }\n            if (name.contains(\"%i\")) {\n                name = name.replace(\"%i\", IsolateUtil.getIsolateID(false));\n            }\n            if (name.contains(\"%I\")) {\n                name = name.replace(\"%I\", IsolateUtil.getIsolateID(true));\n            }\n            if (name.contains(\"%t\")) {\n                name = name.replace(\"%t\", String.valueOf(GraalServices.milliTimeStamp()));\n            }\n\n            for (String subst : new String[]{\"%o\", \"%e\"}) {\n                if (name.contains(subst) && !name.equals(subst)) {\n                    throw new IllegalArgumentException(\"LogFile substitution \" + subst + \" cannot be combined with any other characters\");\n                }\n            }\n\n            return name;\n        }\n\n        /**\n         * An output stream that redirects to {@link HotSpotJVMCIRuntime#getLogStream()}. The\n         * {@link HotSpotJVMCIRuntime#getLogStream()} value is only accessed the first time an IO\n         * operation is performed on the stream. This is required to break a deadlock in early JVMCI\n         * initialization.\n         */\n        class DelayedOutputStream extends OutputStream {\n            private volatile OutputStream lazy;\n\n            private OutputStream lazy() {\n                if (lazy == null) {\n                    synchronized (this) {","sourceCodeStart":124,"sourceCodeEnd":160,"githubUrl":"https://github.com/oracle/graal/blob/a66e9ccd1d7bf2552883939aa0788dfd0e294aab/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/HotSpotTTYStreamProvider.java#L124-L160","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"# before\n-Dgraal.LogFile=graal_%o.log\n\n# after (redirect to stdout wholesale)\n-Dgraal.LogFile=%o\n# or, generated file name\n-Dgraal.LogFile=graal_%i.log","handlingStrategy":"validation","validationCode":"// Java: validate the LogFile value before enabling compiler logging\nString logFile = System.getProperty(\"graal.LogFile\", \"\");\nfor (String wholeOnly : new String[]{\"%o\", \"%e\"}) {\n    if (logFile.contains(wholeOnly) && !logFile.equals(wholeOnly)) {\n        throw new IllegalArgumentException(\n            \"graal.LogFile: \" + wholeOnly + \" must be the entire value, got: \" + logFile);\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    HotSpotTTYStreamProvider.openLogStream(); // or launch JVM with graal.LogFile\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"cannot be combined\")) { /* fix the property, retry */ }\n    throw e;\n}","preventionTips":["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."],"tags":["graalvm","logging","configuration","jvmci"],"backgroundTag":null,"analyzedSha":"a66e9ccd1d7bf2552883939aa0788dfd0e294aab","analyzedAt":"2026-08-14T13:58:47.161Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}