{"record":{"id":"d32a3f100e54c86b","repo":"quarkusio/quarkus","slug":"improper-registration-of-zoneid-substitution","errorCode":null,"errorMessage":"Improper registration of ZoneId substitution","messagePattern":"Improper registration of ZoneId substitution","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"core/deployment/src/main/java/io/quarkus/deployment/recording/substitutions/AdditionalSubstitutionsBuildStep.java","lineNumber":31,"sourceCode":"    public void additionalSubstitutions(BuildProducer<ObjectSubstitutionBuildItem> producer) {\n        zoneIdSubstitutions(producer);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private void zoneIdSubstitutions(BuildProducer<ObjectSubstitutionBuildItem> producer) {\n        try {\n            /*\n             * We can't refer to these classes as they are package private but we need a handle on need\n             * because the bytecode recorder needs to have the actual class registered and not a super class\n             */\n\n            Class<ZoneId> zoneRegionClass = (Class<ZoneId>) Class.forName(\"java.time.ZoneRegion\");\n            producer.produce(new ObjectSubstitutionBuildItem(zoneRegionClass, String.class, ZoneIdSubstitution.class));\n\n            Class<ZoneId> zoneOffsetClass = (Class<ZoneId>) Class.forName(\"java.time.ZoneOffset\");\n            producer.produce(new ObjectSubstitutionBuildItem(zoneOffsetClass, String.class, ZoneIdSubstitution.class));\n        } catch (ClassNotFoundException e) {\n            throw new IllegalStateException(\"Improper registration of ZoneId substitution\", e);\n        }\n    }\n}\n","sourceCodeStart":13,"sourceCodeEnd":35,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/core/deployment/src/main/java/io/quarkus/deployment/recording/substitutions/AdditionalSubstitutionsBuildStep.java#L13-L35","documentation":"AdditionalSubstitutionsBuildStep registers bytecode-recorder substitutions for JDK time types. It reflects on java.time.ZoneId/ZoneRegion/ZoneOffset; if any of these classes cannot be loaded on the JVM running the build, registration is incomplete and it throws IllegalStateException('Improper registration of ZoneId substitution').","triggerScenarios":"Class.forName('java.time.ZoneRegion') or 'java.time.ZoneOffset' throws ClassNotFoundException during augmentation — only possible on a non-standard/broken JDK (pre-Java-8 java.time, stripped JRE modules such as missing java.base entries, exotic runtimes).","commonSituations":"Building on a stripped-down JVM/JDK image missing java.time classes; using an unusual JDK vendor or a jlink-minimized runtime that removed parts of java.base; misconfigured toolchains in CI.","solutions":["Build with a complete standard JDK 11+ that includes full java.time in java.base","Check the JDK with: jshell> Class.forName(\"java.time.ZoneRegion\") — it must succeed","Stop excluding/stripping java.time from your JDK or jlink image","Point JAVA_HOME / Maven toolchains to a standard Temurin/Oracle/OpenJDK build"],"exampleFix":"// before (CI image)\nFROM eclipse-temurin:11-jre-alpine-stripped // java.time partially removed\n// after\nFROM eclipse-temurin:11-jdk // full java.base module\nJAVA_HOME=/usr/lib/jvm/temurin-11-jdk-amd64","handlingStrategy":"validation","validationCode":"// run before building on a new JDK image\nClass.forName(\"java.time.ZoneRegion\");\nClass.forName(\"java.time.ZoneOffset\"); // must not throw ClassNotFoundException","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Build with a complete standard JDK 11+","Never jlink-strip java.time out of java.base for build images","Verify CI toolchains with Class.forName(\"java.time.ZoneRegion\")"],"tags":["build-time","jdk","java-time","substitution"],"backgroundTag":"missing-jdk-class","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"}