{"record":{"id":"50e566e88f347c7c","repo":"apache/flink","slug":"could-not-access-the-model-field-of-avro-record","errorCode":null,"errorMessage":"Could not access the MODEL$ field of avro record","messagePattern":"Could not access the MODEL\\$ field of avro record","errorType":"exception","errorClass":"FlinkRuntimeException","httpStatus":null,"severity":"error","filePath":"flink-formats/flink-avro/src/main/java/org/apache/flink/formats/avro/typeutils/AvroFactory.java","lineNumber":168,"sourceCode":"        return newSchemaOptional.orElseGet(() -> specificData.getSchema(type));\n    }\n\n    /**\n     * Creates a {@link SpecificData} object for a given class. Possibly uses the specific data from\n     * the generated class with logical conversions applied (avro >= 1.9.x).\n     *\n     * <p>Copied over from {@code SpecificData#getForClass(Class<T> c)} we do not use the method\n     * directly, because we want to be API backwards compatible with older Avro versions which did\n     * not have this method\n     */\n    public static <T extends SpecificData> SpecificData getSpecificDataForClass(\n            Class<T> type, ClassLoader cl) {\n        try {\n            Field specificDataField = type.getDeclaredField(\"MODEL$\");\n            specificDataField.setAccessible(true);\n            return (SpecificData) specificDataField.get((Object) null);\n        } catch (IllegalAccessException e) {\n            throw new FlinkRuntimeException(\"Could not access the MODEL$ field of avro record\", e);\n        } catch (NoSuchFieldException e) {\n            return new SpecificData(cl);\n        }\n    }\n\n    /**\n     * Extracts an Avro {@link Schema} from a {@link SpecificRecord}. We do this by creating an\n     * instance of the class using the zero-argument constructor and calling {@link\n     * SpecificRecord#getSchema()} on it.\n     */\n    private static Optional<Schema> tryExtractAvroSchemaViaInstance(Class<?> type) {\n        try {\n            SpecificRecord instance = (SpecificRecord) type.newInstance();\n            return Optional.ofNullable(instance.getSchema());\n        } catch (InstantiationException | IllegalAccessException e) {\n            LOG.warn(\n                    \"Could not extract schema from Avro-generated SpecificRecord class {}: {}.\",\n                    type,","sourceCodeStart":150,"sourceCodeEnd":186,"githubUrl":"https://github.com/apache/flink/blob/2f3c205e9266cb30240eb7f4fdab15cad629a70f/flink-formats/flink-avro/src/main/java/org/apache/flink/formats/avro/typeutils/AvroFactory.java#L150-L186","documentation":"AvroFactory.getSpecificDataForClass reflectively reads the static MODEL$ field of a generated SpecificRecord class to obtain its SpecificData instance. IllegalAccessException means the field exists but the runtime forbids access — classloader isolation or module/JPMS access rules — so Flink wraps it in FlinkRuntimeException. (NoSuchFieldException is handled gracefully by falling back to new SpecificData(cl).)","triggerScenarios":"A user-code classloader (e.g. Flink's child-first classloading, plugin classloader, or per-job classloader isolation) loads the Avro generated class in a way that setAccessible(true) on MODEL$ is denied; also Java module-system boundaries denying deep reflection into the record's package.","commonSituations":"Deploying Avro-generated classes in the user jar with classloader resolution-mode child-first; running on JDK 17+ where illegal reflective access is denied by default; shaded/relocated avro classes where MODEL$ exists under a different runtime context.","solutions":["Ensure exactly one copy of the Avro generated class (and matching avro version) is on the classpath — duplicate classes across parent/child classloaders commonly cause this.","Set classloader.resolve-order to parent-first for the avro artifacts, or package avro + generated classes together consistently.","On JDK 16+, add the required opens/add-opens JVM options (e.g. --add-opens java.base/java.lang=ALL-UNNAMED and opens for the record's package) if modules are in play.","As a workaround, avoid the SpecificRecord path (use GenericRecord with an explicit schema)."],"exampleFix":"# before (flink-conf.yaml)\nclassloader.resolve-order: child-first\n\n# after\nclassloader.resolve-order: parent-first\n# or remove duplicate avro deps from the user jar:\n<dependency><groupId>org.apache.avro</groupId><artifactId>avro</artifactId><scope>provided</scope></dependency>","handlingStrategy":"try-catch","validationCode":"try {\n    Class<?> c = Class.forName(recordClassName, false, userClassLoader);\n    Field f = c.getDeclaredField(\"MODEL$\");\n    f.setAccessible(true);\n} catch (NoSuchFieldException expected) {\n    // fine: AvroFactory falls back to new SpecificData(cl)\n} catch (IllegalAccessException e) {\n    throw new IllegalStateException(\"Classloader/module blocks MODEL$ access; check classloader.resolve-order and duplicate avro jars\", e);\n}","typeGuard":null,"tryCatchPattern":"try {\n    SpecificData sd = AvroFactory.getSpecificDataForClass(type, cl);\n    // proceed\n} catch (FlinkRuntimeException e) {\n    // reflective access denied: fall back to generic path with explicit schema\n    datumWriter = new GenericDatumWriter<>(explicitSchema); // requires schema supplied\n}","preventionTips":["Ship exactly one avro artifact (scope user-jar avro as provided when the cluster provides it).","Match classloader.resolve-order between environments that do and do not work.","On JDK 16+, ensure add-opens permits deep reflection where modules apply."],"tags":["avro","flink","reflection","classloader","jvm-modules"],"backgroundTag":null,"analyzedSha":"2f3c205e9266cb30240eb7f4fdab15cad629a70f","analyzedAt":"2026-08-14T08:48:24.518Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}