apache/beam · error · RuntimeException

Unexpected null number for <field>

Error message

Unexpected null number for <field>

What it means

Thrown by JavaBeanSchema.validateFieldNumbers when a field has no @SchemaFieldNumber annotation, so getNumber() returns null. All fields in a JavaBean schema must carry explicit, contiguous field numbers starting at 0.

Source

Thrown at sdks/java/core/src/main/java/org/apache/beam/sdk/schemas/JavaBeanSchema.java:80

          ReflectUtils.getMethods(typeDescriptor.getRawType()).stream()
              .filter(ReflectUtils::isGetter)
              .filter(m -> !m.isAnnotationPresent(SchemaIgnore.class))
              .collect(Collectors.toList());
      List<FieldValueTypeInformation> types = Lists.newArrayListWithCapacity(methods.size());
      for (int i = 0; i < methods.size(); ++i) {
        types.add(FieldValueTypeInformation.forGetter(typeDescriptor, methods.get(i), i));
      }
      types.sort(JavaBeanUtils.comparingNullFirst(FieldValueTypeInformation::getNumber));
      validateFieldNumbers(types);
      return types;
    }

    private static void validateFieldNumbers(List<FieldValueTypeInformation> types) {
      for (int i = 0; i < types.size(); ++i) {
        FieldValueTypeInformation type = types.get(i);
        @javax.annotation.Nullable Integer number = type.getNumber();
        if (number == null) {
          throw new RuntimeException("Unexpected null number for " + type.getName());
        }
        Preconditions.checkState(
            number == i,
            "Expected field number %s for field %s instead got %s",
            i,
            type.getName(),
            number);
      }
    }

    @Override
    public int hashCode() {
      return System.identityHashCode(this);
    }

    @Override
    public boolean equals(@Nullable Object obj) {
      return obj instanceof GetterTypeSupplier;

View on GitHub (pinned to 12126d8942)

Solutions

  1. Add @SchemaFieldNumber(n) to every getter in the bean, using contiguous numbers 0..N-1.
  2. Ensure numbers match field order (validateFieldNumbers also checks number == index).
  3. Alternatively drop all @SchemaFieldNumber annotations to use default ordering, if the schema does not require stable numbering.

Example fix

// before
public String getName() { ... } // missing annotation

// after
@SchemaFieldNumber(0)
public String getName() { ... }
Defensive patterns

Strategy: validation

Validate before calling

int i = 0; for (Method m : clazz.getMethods()) { if (isGetter(m)) { SchemaFieldNumber n = m.getAnnotation(SchemaFieldNumber.class); if (n == null || n.value() != i++) { throw new IllegalStateException("Field " + m.getName() + " needs @SchemaFieldNumber(" + i + ")"); } } }

Try / catch

try { schemaOf(clazz); } catch (RuntimeException e) { if (e.getMessage().startsWith("Unexpected null number for") || e.getMessage().contains("Expected field number")) { /* add/renumber @SchemaFieldNumber */ } else { throw e; } }

Prevention

When it happens

Trigger: Annotating some but not all getters with @SchemaFieldNumber; schema introspection of the bean via get() then validates numbers and hits the null one.

Common situations: Adding a new field to an existing annotated bean without adding its number; forgetting the annotation on one of many fields; refactoring that removes an annotation.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of apache/beam@12126d8942 (2026-09-13). Data as JSON: /api/errors/b4897166bfa7cf86. Report an issue: GitHub.