apache/beam · error · UnsupportedOperationException

%s is splittable and uses timer family, but these are not co

Error message

%s is splittable and uses timer family, but these are not compatible

What it means

ParDo.validate rejects DoFns that declare a TimerFamily while also being splittable — TimerFamily (multiple timers under one id with dynamic per-timer timestamps) is incompatible with element splitting in Beam's model. Construction fails with UnsupportedOperationException naming the offending DoFn class.

Source

Thrown at sdks/java/core/src/main/java/org/apache/beam/sdk/transforms/ParDo.java:636

      throw new UnsupportedOperationException(
          String.format(
              "%s is splittable and uses state, but these are not compatible",
              fn.getClass().getName()));
    }

    // Timers are semantically incompatible with splitting
    if ((!signature.timerDeclarations().isEmpty() || !signature.timerFamilyDeclarations().isEmpty())
        && signature.processElement().isSplittable()) {
      throw new UnsupportedOperationException(
          String.format(
              "%s is splittable and uses timers, but these are not compatible",
              fn.getClass().getName()));
    }

    // TimerFamily is semantically incompatible with splitting
    if (!signature.timerFamilyDeclarations().isEmpty()
        && signature.processElement().isSplittable()) {
      throw new UnsupportedOperationException(
          String.format(
              "%s is splittable and uses timer family, but these are not compatible",
              fn.getClass().getName()));
    }
  }

  /**
   * Extract information on how the DoFn uses schemas. In particular, if the schema of an element
   * parameter does not match the input PCollection's schema, convert.
   */
  @Internal
  public static DoFnSchemaInformation getDoFnSchemaInformation(
      DoFn<?, ?> fn, PCollection<?> input) {
    DoFnSignature signature = DoFnSignatures.getSignature(fn.getClass());
    DoFnSignature.ProcessElementMethod processElementMethod = signature.processElement();
    if (!processElementMethod.getSchemaElementParameters().isEmpty()) {
      if (!input.hasSchema()) {
        throw new IllegalArgumentException("Type of @Element must match the DoFn type" + input);

View on GitHub (pinned to 12126d8942)

Solutions

  1. Move TimerFamily usage to a separate non-splittable DoFn applied after the splittable stage
  2. Remove the TimerFamily declarations from the splittable DoFn
  3. Use per-restriction checkpointing/resume instead of timer families for the splittable logic

Example fix

// before
class Sdf extends DoFn<T, O> { @TimerFamily "tf"; @ProcessElement ProcessContinuation processElement(RestrictionTracker r, TimerMap tm, ...) }
// after
class Sdf extends DoFn<T, O> { @ProcessElement ProcessContinuation processElement(RestrictionTracker r, ...) } // TimerFamily moved downstream
Defensive patterns

Strategy: validation

Validate before calling

DoFnSignature sig = DoFnSignatures.getSignature((Class) fn.getClass());
if (!sig.timerFamilyDeclarations().isEmpty() && sig.processElement().isSplittable()) {
  throw new IllegalArgumentException(fn.getClass() + " cannot use TimerFamily and be splittable");
}

Type guard

boolean timerFamilyAndSplittable(DoFn<?, ?> fn) {
  DoFnSignature sig = DoFnSignatures.getSignature((Class) fn.getClass());
  return !sig.timerFamilyDeclarations().isEmpty() && sig.processElement().isSplittable();
}

Try / catch

try {
  pipeline.apply(ParDo.of(fn));
} catch (UnsupportedOperationException e) {
  if (e.getMessage() != null && e.getMessage().endsWith("splittable and uses timer family, but these are not compatible")) {
    throw new IllegalStateException("Move TimerFamily usage downstream", e);
  }
  throw e;
}

Prevention

When it happens

Trigger: ParDo.of(fn) where fn declares @TimerFamily fields and its @ProcessElement uses a RestrictionTracker (isSplittable).

Common situations: Using TimerFamily APIs (dynamic timer keys) inside a splittable source/reader DoFn; migrating timer code into an SDF.

Understand the failure class

Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.

Related errors


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