apache/beam · error
invalid output type in method
Error message
invalid output type in method %v, return value at index %v (type: %v). Output of method %v must implement sdf.WatermarkEstimator.
What it means
During validation of a Beam Go SDF (Splittable DoFn), the CreateWatermarkEstimator method must return exactly one value implementing sdf.WatermarkEstimator. This error is raised when the first return value's type does not implement that interface. Beam checks this at graph-construction time so bad DoFn signatures fail fast before pipeline execution.
Solutions
- Make the CreateWatermarkEstimator return value implement sdf.WatermarkEstimator: it needs method Watermark() typex.EventTime.
- Check whether Watermark() is defined on a pointer receiver while the method returns a value type (or the reverse); make the return type match the receiver type.
- If doing stateful estimation, return a state-aware estimator type instead of a plain value.
- Verify against the current Beam SDK version's sdf.WatermarkEstimator interface in case the interface surface changed.
Example fix
// before
func (f *fn) CreateWatermarkEstimator(rest MyRestriction) int64 {
return 0
}
// after
func (f *fn) CreateWatermarkEstimator(rest MyRestriction) sdf.WatermarkEstimator {
return &myWatermarkEstimator{watermark: typex.MinTimestamp}
}
// with
type myWatermarkEstimator struct{ watermark typex.EventTime }
func (e *myWatermarkEstimator) Watermark() typex.EventTime { return e.watermark } Defensive patterns
Strategy: validation
Validate before calling
var _ sdf.WatermarkEstimator = (*myWatermarkEstimator)(nil) var _ func(MyRestriction) sdf.WatermarkEstimator = (*fn).CreateWatermarkEstimator
Type guard
func implementsWatermarkEstimator(v any) bool {
_, ok := v.(sdf.WatermarkEstimator)
return ok
} Prevention
- Assert interface satisfaction at compile time with var _ sdf.WatermarkEstimator = (*T)(nil).
- Keep the Watermark() receiver type identical to the CreateWatermarkEstimator return type.
- Copy signatures from an up-to-date Beam SDF example rather than from memory.
- Run graph validation early in tests; these errors surface before any data flows.
When it happens
Trigger: Defining an SDF whose CreateWatermarkEstimator() method returns a concrete type (or pointer) that does not implement sdf.WatermarkEstimator, e.g. returning a custom struct without a Watermark() typex.EventTime method, or returning a value type when the interface methods are on a pointer receiver.
Common situations: Hand-writing an SDF copied from an example but renaming the estimator type; implementing Watermark() with a wrong signature; returning the estimator by value when methods are defined on pointer receiver; upgrading Beam where the WatermarkEstimator interface gained methods.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- mismatched event time type in method
- mismatched output type in method
- mismatched watermark state type in method
- Invalid output type in method
- Invalid output type in method
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/06d2c3c652c23200.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/go/pkg/beam/core/graph/fn.go:1213
err := errors.Errorf("stateful watermark estimation method %v is present, "+
"but CreateWatermarkEstimator doesn't take in a state parameter.", initialWatermarkEstimatorStateName)
return err
}
if _, ok := fn.methods[watermarkEstimatorStateName]; ok {
err := errors.Errorf("stateful watermark estimation method %v is present, "+
"but CreateWatermarkEstimator doesn't take in a state parameter.", watermarkEstimatorStateName)
return err
}
}
if len(method.Ret) != returnNum {
err := errors.Errorf("unexpected number of returns in method %v. got: %v, want: %v",
createWatermarkEstimatorName, len(method.Ret), returnNum)
return errors.SetTopLevelMsgf(err, "unexpected number of return values in method %v. "+
"got: %v, want: %v. Check that the signature conforms to the expected signature for %v.",
createWatermarkEstimatorName, len(method.Ret), returnNum, createWatermarkEstimatorName)
} else if !method.Ret[0].T.Implements(watermarkEstimatorT) {
err := errors.Errorf("invalid output type in method %v, return %v: %v does not implement sdf.WatermarkEstimator",
createWatermarkEstimatorName, 0, method.Ret[0].T)
return errors.SetTopLevelMsgf(err, "invalid output type in method %v, "+
"return value at index %v (type: %v). Output of method %v must implement sdf.WatermarkEstimator.",
createWatermarkEstimatorName, 0, method.Ret[0].T, createWatermarkEstimatorName)
}
processFn := fn.methods[processElementName]
pos, _ := processFn.WatermarkEstimator()
if pos != -1 && method.Ret[0].T != processFn.Param[pos].T {
err := errors.Errorf("mismatched output type in method %v, return %v: got: %v, want: %v",
watermarkEstimatorStateName, 0, method.Ret[0].T, processFn.Param[pos].T)
return errors.SetTopLevelMsgf(err, "Mismatched output type in method %v, "+
"return value at index %v. Got: %v, Want: %v (from method %v).",
watermarkEstimatorStateName, 0, method.Ret[0].T, processFn.Param[pos].T, processElementName)
}
return nil
}View on GitHub (pinned to 12126d8942)