apache/beam · error · UnsupportedOperationException
%s is splittable and uses timers, but these are not compatib
Error message
%s is splittable and uses timers, but these are not compatible
What it means
ParDo.validate rejects DoFns that use timers (via @TimerId or @TimerFamily declarations detected through signature.timerDeclarations()/timerFamilyDeclarations()) while being splittable, as timers conflict with the element-splitting semantics. The pipeline cannot be constructed.
Source
Thrown at sdks/java/core/src/main/java/org/apache/beam/sdk/transforms/ParDo.java:627
/**
* Perform common validations of the {@link DoFn}, for example ensuring that state is used
* correctly and that its features can be supported.
*/
private static <InputT, OutputT> void validate(DoFn<InputT, OutputT> fn) {
DoFnSignature signature = DoFnSignatures.getSignature((Class) fn.getClass());
// State is semantically incompatible with splitting
if (!signature.stateDeclarations().isEmpty() && signature.processElement().isSplittable()) {
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.View on GitHub (pinned to 12126d8942)
Solutions
- Move timers into a separate, non-splittable stateful ParDo downstream of the splittable DoFn
- Remove the timer declarations from the splittable DoFn
- Replace timer-based logic with restriction/resume semantics native to SDFs (e.g. ProcessContinuation.resumedelayed)
Example fix
// before
class Sdf extends DoFn<T, O> { @TimerId "t"; @ProcessElement ProcessContinuation processElement(RestrictionTracker r, Timer t, ...) }
// after
class Sdf extends DoFn<T, O> { @ProcessElement ProcessContinuation processElement(RestrictionTracker r, ...) } // timers moved to downstream DoFn Defensive patterns
Strategy: validation
Validate before calling
DoFnSignature sig = DoFnSignatures.getSignature((Class) fn.getClass());
if ((!sig.timerDeclarations().isEmpty() || !sig.timerFamilyDeclarations().isEmpty())
&& sig.processElement().isSplittable()) {
throw new IllegalArgumentException(fn.getClass() + " cannot use timers and be splittable");
} Type guard
boolean timersAndSplittable(DoFn<?, ?> fn) {
DoFnSignature sig = DoFnSignatures.getSignature((Class) fn.getClass());
return (!sig.timerDeclarations().isEmpty() || !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 timers, but these are not compatible")) {
throw new IllegalStateException("Move timers to a downstream non-splittable DoFn", e);
}
throw e;
} Prevention
- Never add @TimerId to DoFns using RestrictionTracker
- Isolate timer logic in dedicated stateful stages
- Test pipeline construction in CI to surface validate() failures early
When it happens
Trigger: ParDo.of(fn) where fn declares timer fields (@TimerId/@TimerFamily) and its @ProcessElement is splittable (uses a RestrictionTracker / returns ProcessContinuation).
Common situations: Adding event-time timers to a splittable file or streaming-source DoFn; porting a stateful/timer-based DoFn to an SDF pattern.
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
- %s is splittable and uses timer family, but these are not co
- Cannot access timerId as parameter outside of @OnTimer metho
- Not expected to access TimeDomain from @ProcessElement
- %s is splittable and uses state, but these are not compatibl
- Expected size >= 0 but received ${size}.
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/902a98718716a478.
Report an issue: GitHub.