{"record":{"id":"4829997bef5ae057","repo":"apache/beam","slug":"class-descriptor-has-final-fields-and-no-registered-creator","errorCode":null,"errorMessage":"Class <descriptor> has final fields and no registered creator. Cannot use as schema, as we don't know how to create this object automatically","messagePattern":"Class <descriptor> has final fields and no registered creator\\. Cannot use as schema, as we don't know how to create this object automatically","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"sdks/java/core/src/main/java/org/apache/beam/sdk/schemas/JavaFieldSchema.java","lineNumber":85,"sourceCode":"      for (int i = 0; i < fields.size(); ++i) {\n        types.add(FieldValueTypeInformation.forField(typeDescriptor, fields.get(i), i));\n      }\n      types.sort(JavaBeanUtils.comparingNullFirst(FieldValueTypeInformation::getNumber));\n      validateFieldNumbers(types);\n\n      // If there are no creators registered, then make sure none of the schema fields are final,\n      // as we (currently) have no way of creating classes in this case.\n      if (ReflectUtils.getAnnotatedCreateMethod(typeDescriptor.getRawType()) == null\n          && ReflectUtils.getAnnotatedConstructor(typeDescriptor.getRawType()) == null) {\n        Optional<Field> finalField =\n            types.stream()\n                .flatMap(\n                    fvti ->\n                        Optional.ofNullable(fvti.getField()).map(Stream::of).orElse(Stream.empty()))\n                .filter(f -> Modifier.isFinal(f.getModifiers()))\n                .findAny();\n        if (finalField.isPresent()) {\n          throw new IllegalArgumentException(\n              \"Class \"\n                  + typeDescriptor\n                  + \" has final fields and no \"\n                  + \"registered creator. Cannot use as schema, as we don't know how to create this \"\n                  + \"object automatically\");\n        }\n      }\n      return types;\n    }\n  }\n\n  private static void validateFieldNumbers(List<FieldValueTypeInformation> types) {\n    for (int i = 0; i < types.size(); ++i) {\n      FieldValueTypeInformation type = types.get(i);\n      @Nullable Integer number = type.getNumber();\n      if (number == null) {\n        throw new RuntimeException(\"Unexpected null number for \" + type.getName());\n      }","sourceCodeStart":67,"sourceCodeEnd":103,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/core/src/main/java/org/apache/beam/sdk/schemas/JavaFieldSchema.java#L67-L103","documentation":"JavaFieldSchema builds a schema by reflecting over a class's fields and constructs instances without a user-supplied creator. If any field is final, Beam cannot assign it reflectively without a registered creator method, so it rejects the class with an IllegalArgumentException.","triggerScenarios":"Registering or inferring JavaFieldSchema for a class that has final instance fields and no @SchemaCreate/creator method registered in SchemaRegistry.","commonSituations":"Immutable value classes (final fields set in constructor) used in PCollections without a custom schema provider; upgrading an existing class to make fields final.","solutions":["Remove the final modifier from the fields, or","Register a creator method (static method annotated with @SchemaCreate returning an instance) with SchemaRegistry so Beam can construct objects.","Alternatively annotate the class to use a different schema provider that supports immutables (e.g. @DefaultSchema(RecordSchema.class) or a custom SchemaUserTypeCreator)."],"exampleFix":"// before\npublic class User { private final String name; }\n\n// after\npublic class User { private String name; }\n// or register:\n@SchemaCreate\npublic static User create(String name) { return new User(name); }","handlingStrategy":"validation","validationCode":"// Java: ensure a creator exists when fields are final\nboolean hasFinal = java.util.Arrays.stream(User.class.getDeclaredFields())\n    .anyMatch(f -> java.lang.reflect.Modifier.isFinal(f.getModifiers()));\nboolean hasCreator = java.util.Arrays.stream(User.class.getDeclaredMethods())\n    .anyMatch(m -> m.isAnnotationPresent(org.apache.beam.sdk.schemas.annotations.SchemaCreate.class));\nif (hasFinal && !hasCreator) throw new IllegalStateException(\"Register @SchemaCreate for final-field class\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Prefer non-final fields or register @SchemaCreate for immutable classes.","Test schema inference for new POJOs before deploying pipelines."],"tags":["java","schema","reflection","immutability"],"backgroundTag":"schema-validation-failed","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}