apache/beam · error · java.lang.IllegalArgumentException

is not permitted for user timers

Error message

%s is not permitted for user timers

What it means

Beam's user-facing Timer API supports EVENT_TIME and PROCESSING_TIME domains only. timerFamilyTimeDomainToProto maps the Java TimeDomain enum to the proto enum, and SYNCHRONIZED_PROCESSING_TIME — an internal domain used by runners/test streams — is explicitly rejected for user timers with this IllegalArgumentException.

Solutions

  1. Change the timer to TimeDomain.EVENT_TIME or TimeDomain.PROCESSING_TIME
  2. Only use SYNCHRONIZED_PROCESSING_TIME in runner/test-stream internals, not user DoFn timers
  3. Review the @TimerFamily signature and the TimeDomain import used in the DoFn

Example fix

// before
@TimerFamily("alarm") Timer family; // declared with TimeDomain.SYNCHRONIZED_PROCESSING_TIME
// after
timer = dofnTimer.withTimeDomain(TimeDomain.EVENT_TIME); // or PROCESSING_TIME
Defensive patterns

Strategy: validation

Validate before calling

if (timeDomain == TimeDomain.SYNCHRONIZED_PROCESSING_TIME) throw new IllegalArgumentException("SYNCHRONIZED_PROCESSING_TIME not allowed for user timers");

Type guard

boolean isUserTimerDomain(TimeDomain d) { return d == TimeDomain.EVENT_TIME || d == TimeDomain.PROCESSING_TIME; }

Try / catch

try { String proto = ParDoTranslation.timerFamilyTimeDomainToProto(timeDomain); } catch (IllegalArgumentException e) { /* switch to EVENT_TIME */ }

Prevention

When it happens

Trigger: Defining or translating a @Timer whose TimeDomain parameter is TimeDomain.SYNCHRONIZED_PROCESSING_TIME (e.g. via TimerSpec/@TimerFamily or a DoFn signature) so translateTimerFamilySpec hits the forbidden case.

Common situations: Copy-pasting timer signatures from runner internals/test-stream code; constructing a TimerSpec programmatically with the wrong TimeDomain constant; migrating code that used internal timer APIs.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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

Appendix: source

Thrown at sdks/java/core/src/main/java/org/apache/beam/sdk/util/construction/ParDoTranslation.java:746

      TimerSpec timer,
      SdkComponents components,
      Coder<?> keyCoder,
      Coder<BoundedWindow> windowCoder) {
    return RunnerApi.TimerFamilySpec.newBuilder()
        .setTimeDomain(translateTimeDomain(timer.getTimeDomain()))
        .setTimerFamilyCoderId(
            registerCoderOrThrow(components, Timer.Coder.of(keyCoder, windowCoder)))
        .build();
  }

  public static RunnerApi.TimeDomain.Enum translateTimeDomain(TimeDomain timeDomain) {
    switch (timeDomain) {
      case EVENT_TIME:
        return RunnerApi.TimeDomain.Enum.EVENT_TIME;
      case PROCESSING_TIME:
        return RunnerApi.TimeDomain.Enum.PROCESSING_TIME;
      case SYNCHRONIZED_PROCESSING_TIME:
        throw new IllegalArgumentException(
            String.format(
                "%s is not permitted for user timers",
                TimeDomain.SYNCHRONIZED_PROCESSING_TIME.name()));
      default:
        throw new IllegalArgumentException("Unknown time domain");
    }
  }

  public static FunctionSpec translateDoFn(
      DoFn<?, ?> fn,
      TupleTag<?> tag,
      Map<String, PCollectionView<?>> sideInputMapping,
      DoFnSchemaInformation doFnSchemaInformation,
      SdkComponents components) {
    return FunctionSpec.newBuilder()
        .setUrn(CUSTOM_JAVA_DO_FN_URN)
        .setPayload(
            ByteString.copyFrom(

View on GitHub (pinned to 12126d8942)