{"record":{"id":"1d69c587d0c1c6a3","repo":"quarkusio/quarkus","slug":"unable-to-set-tmp-java-home-for-fontconfig-quarkus","errorCode":null,"errorMessage":"Unable to set tmp java.home for FontConfig Quarkus AWT usage in ${javaHome}","messagePattern":"Unable to set tmp java\\.home for FontConfig Quarkus AWT usage in (.+?)","errorType":"exception","errorClass":"UncheckedIOException","httpStatus":null,"severity":"error","filePath":"extensions/awt/runtime/src/main/java/io/quarkus/awt/runtime/JDKSubstitutions.java","lineNumber":69,"sourceCode":" */\n@TargetClass(className = \"sun.awt.FontConfiguration\", onlyWith = IsLinux.class)\nfinal class Target_sun_awt_FontConfiguration_Linux {\n    @Alias\n    protected static String osVersion;\n    @Alias\n    protected static String osName;\n\n    @Substitute\n    protected void setOsNameAndVersion() {\n        final Path javaHome = Path.of(System.getProperty(\"java.io.tmpdir\"), \"quarkus-awt-tmp-fonts\");\n        try {\n            System.setProperty(\"java.home\", javaHome.toString());\n            osName = System.getProperty(\"os.name\", \"unknown\");\n            osVersion = System.getProperty(\"os.version\");\n            Files.createDirectories(javaHome.resolve(\"lib\"));\n            Files.createDirectories(javaHome.resolve(\"conf\").resolve(\"fonts\"));\n        } catch (IOException e) {\n            throw new UncheckedIOException(\"Unable to set tmp java.home for FontConfig Quarkus AWT usage in \" + javaHome, e);\n        }\n    }\n}\n\n/**\n * See Target_sun_awt_FontConfiguration_Linux, for context.\n *\n * Windows doesn't have fontconfig package and its config file installed like Linux has.\n * Java runtime looks for the config file inside our fake JAVA_HOME.\n * We provide a skeleton, i18n ignorant version to satisfy the basic headless fonts processing.\n */\n@TargetClass(className = \"sun.awt.FontConfiguration\", onlyWith = IsWindows.class)\nfinal class Target_sun_awt_FontConfiguration_Windows {\n    @Alias\n    protected static String osVersion;\n    @Alias\n    protected static String osName;\n","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/awt/runtime/src/main/java/io/quarkus/awt/runtime/JDKSubstitutions.java#L51-L87","documentation":"On native image, Quarkus AWT's substitution for sun.awt.FontConfiguration (Linux) creates a temporary java.home layout (lib/ and conf/fonts directories) that FontConfig requires. If creating these directories fails with IOException, an UncheckedIOException with this message is thrown, aborting font initialization.","triggerScenarios":"First AWT/Font usage in a native executable where the temp directory (usually io.tmpdir under the app dir) cannot be created: read-only filesystem, permission denied, or no space.","commonSituations":"Running the native binary in a read-only container (distroless, read-only /tmp); running as a non-root user without write access; security-hardened runtime blocking directory creation.","solutions":["Ensure the directory backing java.io.tmpdir (or the path reported) is writable by the process user","Mount a writable tmpfs at /tmp in the container (e.g. docker run --tmpfs /tmp:rw)","Check disk space and permissions; run the binary with a user that owns its directory","If java.home was mis-resolved, verify how the native binary locates its temp dir and pass -Djava.io.tmpdir to a writable path"],"exampleFix":"// before (read-only rootfs)\ndocker run --read-only myapp-image\n// after\ndocker run --read-only --tmpfs /tmp:rw,noexec,nosuid myapp-image","handlingStrategy":"validation","validationCode":"Path tmp = Path.of(System.getProperty(\"java.io.tmpdir\"));\nif (!Files.isWritable(tmp)) {\n    throw new IllegalStateException(\"Writable temp dir required for AWT/FontConfig in native mode: \" + tmp);\n}","typeGuard":null,"tryCatchPattern":"try {\n    BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);\n    Graphics2D g = img.createGraphics();\n} catch (UncheckedIOException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"Unable to set tmp java.home\")) {\n        log.error(\"Mount a writable /tmp or grant write access: \" + e.getCause());\n    }\n    throw e;\n}","preventionTips":["Always provide a writable /tmp (tmpfs) to native containers using AWT","Check SELinux/AppArmor policies for temp-dir writes in production images","Verify disk space and user permissions before deploying native binaries","Warm up font initialization in a startup health check to fail fast"],"tags":["awt","fontconfig","graalvm","native-image","filesystem","quarkus"],"backgroundTag":"temp-directory-not-writable","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}