apache/beam · error · RuntimeException
Unexpected time domain
Error message
Unexpected time domain
What it means
FnApiTimerBundleTracker.getModifiedTimersOrdered dispatches on the timer's TimeDomain to return the modified timers in order. If the time domain is none of EVENT_TIME, PROCESSING_TIME, or SYNCHRONIZED_PROCESSING_TIME (e.g. an unknown enum from a newer proto or an unset field), it throws a RuntimeException. This is an internal exhaustive-switch guard.
Solutions
- Align runner and SDK harness versions so the TimeDomain enum is understood.
- Inspect the timer payload/timers sent by the runner for an unset or unknown domain.
- Upgrade Beam to a release handling the domain listed in the failure.
- If custom runner integration, restrict emitted domains to the three standard ones.
Example fix
// before: reading raw proto enum without default handling
// after: upgrade harness to enumerate new domains
switch (domain) {
case EVENT_TIME: ...;
case PROCESSING_TIME: ...;
case SYNCHRONIZED_PROCESSING_TIME: ...;
default: /* upgrade or reject */
} Defensive patterns
Strategy: try-catch
Type guard
boolean isKnownDomain(TimeDomain d) {
return d == TimeDomain.EVENT_TIME
|| d == TimeDomain.PROCESSING_TIME
|| d == TimeDomain.SYNCHRONIZED_PROCESSING_TIME;
} Try / catch
try {
// timer handling
} catch (RuntimeException e) {
if (e.getMessage() != null && e.getMessage().startsWith("Unexpected time domain")) {
LOG.error("Unknown TimeDomain from runner: {}", e.getMessage(), e);
} else { throw e; }
} Prevention
- Only emit the three standard time domains from custom runners
- Keep proto enums in sync with the harness version
- Validate timer payloads at the runner boundary
When it happens
Trigger: A timer fire or timer modification carries a TimeDomain value outside the three known domains when the tracker collects ordered modified timers for bundle completion.
Common situations: Runner emitting newer TimeDomain enum values against an older harness; null/unset time domain from a malformed timer update; version-skewed deployments.
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
- Cannot access timer in non-window observing context.
- Cannot access timerFamily in non-window observing context.
- failed to decode special type, unknown type
- invalid bundle processing state
- JDBC type must be one of
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/ee036e11af896788.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/java/harness/src/main/java/org/apache/beam/fn/harness/state/FnApiTimerBundleTracker.java:79
@AutoValue
public abstract static class Modifications<K> {
public abstract NavigableSet<TimerInfo<K>> getModifiedEventTimersOrdered();
public abstract NavigableSet<TimerInfo<K>> getModifiedProcessingTimersOrdered();
public abstract NavigableSet<TimerInfo<K>> getModifiedSynchronizedProcessingTimersOrdered();
public NavigableSet<TimerInfo<K>> getModifiedTimersOrdered(TimeDomain timeDomain) {
switch (timeDomain) {
case EVENT_TIME:
return getModifiedEventTimersOrdered();
case PROCESSING_TIME:
return getModifiedProcessingTimersOrdered();
case SYNCHRONIZED_PROCESSING_TIME:
return getModifiedSynchronizedProcessingTimersOrdered();
default:
throw new RuntimeException("Unexpected time domain " + timeDomain);
}
}
public abstract Table<String, String, Timer<K>> getModifiedTimerIds();
@SuppressWarnings({"nullness"})
static <K> Modifications<K> create() {
Comparator<TimeDomain> timeDomainComparator =
(td1, td2) -> {
// We prioritize processing-time timers,as those tend to be more latency sensitive.
if (td1 == TimeDomain.PROCESSING_TIME && td2 == TimeDomain.EVENT_TIME) {
return -1;
} else if (td1 == TimeDomain.EVENT_TIME && td2 == TimeDomain.PROCESSING_TIME) {
return 1;
} else {
return td1.compareTo(td2);
}
};View on GitHub (pinned to 12126d8942)