apache/beam · error · RuntimeException

Malformed class : timer declaration field is not accessible.

Error message

Malformed %s class %s: timer declaration field %s is not accessible.

What it means

Beam reads a DoFn's @TimerId-decorated field reflectively to obtain its TimerSpec. If the field cannot be accessed (IllegalAccessException from Field.get), Beam throws a RuntimeException saying the DoFn class is malformed because the timer declaration field is not accessible.

Solutions

  1. Make the @TimerId field public
  2. Verify the field is of type TimerSpec (e.g. TimerSpecs.timer(...)) and lives directly on the DoFn
  3. Ensure the DoFn class and field are accessible to Beam's reflection code
  4. Re-run pipeline construction; error will disappear once reflection succeeds

Example fix

// before
@TimerId("alarm")
private final TimerSpec alarmSpec = TimerSpecs.timer(TimeDomain.EVENT_TIME);

// after
@TimerId("alarm")
public final TimerSpec alarmSpec = TimerSpecs.timer(TimeDomain.EVENT_TIME);
Defensive patterns

Strategy: validation

Validate before calling

for (Field f : MyFn.class.getDeclaredFields()) {
  if (f.isAnnotationPresent(TimerId.class) && !Modifier.isPublic(f.getModifiers())) {
    throw new IllegalStateException("@TimerId field must be public: " + f.getName());
  }
}

Type guard

static boolean isAccessibleTimerField(Field f) {
  return Modifier.isPublic(f.getModifiers()) && f.getType() == TimerSpec.class;

Try / catch

try {
  pipeline.run();
} catch (RuntimeException e) {
  if (e.getMessage().contains("timer declaration field")) {
    // widen the field's visibility to public
  }
}

Prevention

When it happens

Trigger: Declaring a @TimerId field that is private/protected/package-private, then invoking a pipeline that triggers getTimerSpec via reflection, so timerDeclaration.field().get(target) throws IllegalAccessException.

Common situations: Private timer fields written by developers used to encapsulation; code reviews/suppressing warnings pushing fields to private; copy-pasting state fields pattern but applying wrong access to timer fields.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

Thrown at sdks/java/core/src/main/java/org/apache/beam/sdk/transforms/reflect/DoFnSignatures.java:2555

              format(DoFn.class), target.getClass().getName(), stateDeclaration.field().getName()));
    }
  }

  public static TimerSpec getTimerSpecOrThrow(
      TimerDeclaration timerDeclaration, DoFn<?, ?> target) {
    try {
      Object fieldValue = timerDeclaration.field().get(target);
      checkState(
          fieldValue instanceof TimerSpec,
          "Malformed %s class %s: timer declaration field %s does not have type %s.",
          format(DoFn.class),
          target.getClass().getName(),
          timerDeclaration.field().getName(),
          TimerSpec.class);

      return (TimerSpec) timerDeclaration.field().get(target);
    } catch (IllegalAccessException exc) {
      throw new RuntimeException(
          String.format(
              "Malformed %s class %s: timer declaration field %s is not accessible.",
              format(DoFn.class), target.getClass().getName(), timerDeclaration.field().getName()));
    }
  }

  public static TimerSpec getTimerFamilySpecOrThrow(
      TimerFamilyDeclaration timerFamilyDeclaration, DoFn<?, ?> target) {
    try {
      Object fieldValue = timerFamilyDeclaration.field().get(target);
      checkState(
          fieldValue instanceof TimerSpec,
          "Malformed %s class %s: timer declaration field %s does not have type %s.",
          format(DoFn.class),
          target.getClass().getName(),
          timerFamilyDeclaration.field().getName(),
          TimerSpec.class);

View on GitHub (pinned to 12126d8942)