apache/beam · error · UnsupportedOperationException
RecordOffset unsupported in %s
Error message
RecordOffset unsupported in %s
What it means
This is thrown by DoFnInvoker's UnsupportedInvocationBehavior when a DoFn callback calls currentRecordOffset() and the invoking context cannot supply record offsets. Record offsets exist only in splittable-DoFn element processing against an offset-based restriction; default invocation behavior deliberately rejects such calls rather than returning a bogus value. The message's %s names the error context (DoFn class and callback) so you can see which callback misused the accessor.
Source
Thrown at sdks/java/core/src/main/java/org/apache/beam/sdk/transforms/reflect/DoFnInvoker.java:360
throw new UnsupportedOperationException(
String.format("Timestamp unsupported in %s", getErrorContext()));
}
@Override
public @Nullable String currentRecordId(DoFn<InputT, OutputT> doFn) {
throw new UnsupportedOperationException(
String.format("RecordId unsupported in %s", getErrorContext()));
}
@Override
public @Nullable Long currentRecordOffset(DoFn<InputT, OutputT> doFn) {
throw new UnsupportedOperationException(
String.format("RecordOffset unsupported in %s", getErrorContext()));
}
@Override
public Instant fireTimestamp(DoFn<InputT, OutputT> doFn) {
throw new UnsupportedOperationException(
String.format("FireTimestamp unsupported in %s", getErrorContext()));
}
@Override
public CausedByDrain causedByDrain(DoFn<InputT, OutputT> doFn) {
throw new UnsupportedOperationException(
String.format("CausedByDrain unsupported in %s", getErrorContext()));
}
@Override
public ValueKind valueKind(DoFn<InputT, OutputT> doFn) {
throw new UnsupportedOperationException(
String.format("ValueKind unsupported in %s", getErrorContext()));
}
@Override
public String timerId(DoFn<InputT, OutputT> doFn) {
throw new UnsupportedOperationException(View on GitHub (pinned to 12126d8942)
Solutions
- Delete the currentRecordOffset() call or replace it with tracking inside your own restriction tracker
- If you truly need offsets, implement the DoFn as a splittable DoFn and run it through a runner path that uses the SDF DoFnRunner, not the default invoker
- In tests, use DoFnTestUtils.runFunction or TestPipeline so bundle-data-capable runners drive the DoFn
- Catch UnsupportedOperationException around the accessor and degrade gracefully if offsets are optional
Example fix
// before long offset = context.currentRecordOffset(); // after // track progress via your RestrictionTracker instead Progress p = restrictionTracker.getProgress();
Defensive patterns
Strategy: try-catch
Validate before calling
// Ensure the callback is only invoked by a bundle-data-capable runner path, // e.g. run through TestPipeline instead of a hand-built invoker: Pipeline p = TestPipeline.create(); p.apply(Create.of(...)).apply(ParDo.of(myDoFn)); // runner supplies offsets if supported
Type guard
boolean hasRecordOffsets(DoFn<?, ?> fn) {
return fn instanceof org.apache.beam.sdk.transforms.DoFn.HasKeys // or check SDF signature: element+restriction+tracker params
|| java.util.Arrays.stream(fn.getClass().getDeclaredMethods())
.anyMatch(m -> m.isAnnotationPresent(DoFn.ProcessElement.class)
&& m.getParameterCount() > 1);
} Try / catch
try {
long offset = context.currentRecordOffset();
} catch (UnsupportedOperationException e) {
// degrade: treat as unknown offset
processWithoutOffset();
} Prevention
- Reserve currentRecordOffset() for offset-based splittable DoFns only
- Prefer RestrictionTracker.getProgress() for position info instead of raw record offsets
- Use runner-backed test utilities (TestPipeline, DoFnTestUtils) rather than the default invoker
When it happens
Trigger: A @ProcessElement, @OnTimer, @StartBundle, or @FinishBundle callback (or a callback parameter object like DoFn.OnTimerContext) invokes context.currentRecordOffset() while the invoker was created with UnsupportedInvocationBehavior — typically when the DoFn is invoked outside a real runner pipeline, or the DoFn is not actually a splittable DoFn.
Common situations: Porting code from a splittable DoFn into an ordinary DoFn but keeping currentRecordOffset(); running DoFns in a custom harness or SDK-conformance test using DoFnInvokers.invokerFor(...) without bundle-data support; third-party runner implementations that do not implement record offsets.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- RecordId unsupported in %s
- ValueKind unsupported in %s
- Not expected to access Restriction from a regular DoFn in Do
- Not expected to access RestrictionTracker from a regular DoF
- SideInput unsupported in ${context}
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/16e803341db8be0a.
Report an issue: GitHub.