{"record":{"id":"2e501a474a788b90","repo":"apache/beam","slug":"missing-output-value-in-method-v-v-method-should-return-v","errorCode":null,"errorMessage":"Missing output value in method %v, %v method should return %v when %v method is defined.","messagePattern":"Missing output value in method (.+?), (.+?) method should return (.+?) when (.+?) method is defined\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sdks/go/pkg/beam/core/graph/fn.go","lineNumber":1109,"sourceCode":"\t\t\tif method.Param[startIdx].T != rTrackerImplT {\n\t\t\t\terr := errors.Errorf(\"mismatched restriction tracker type in method %v, param %v. got: %v, want: %v\",\n\t\t\t\t\ttruncateRestrictionName, startIdx, method.Param[startIdx].T, rTrackerImplT)\n\t\t\t\treturn errors.SetTopLevelMsgf(err, \"Mismatched restriction tracker type in method %v, \"+\n\t\t\t\t\t\"parameter at index %v. Got: %v, Want: %v (from method %v). \"+\n\t\t\t\t\t\"Ensure that restriction tracker is the first parameter.\",\n\t\t\t\t\ttruncateRestrictionName, startIdx, method.Param[startIdx].T, rTrackerImplT, createTrackerName)\n\t\t\t}\n\t\t\tif method.Ret[0].T != restrictionT {\n\t\t\t\terr := errors.Errorf(\"invalid output type in method %v, return %v. got: %v, want: %v\",\n\t\t\t\t\ttruncateRestrictionName, 0, method.Ret[0].T, restrictionT)\n\t\t\t\treturn errors.SetTopLevelMsgf(err, \"Invalid output type in method %v, \"+\n\t\t\t\t\t\"return value at index %v. Got: %v, Want: %v (from method %v). \"+\n\t\t\t\t\t\"Ensure that all restrictions in an SDF are the same type.\",\n\t\t\t\t\ttruncateRestrictionName, 0, method.Ret[0].T, restrictionT, createInitialRestrictionName)\n\t\t\t}\n\t\t\tprocessFn := fn.methods[processElementName]\n\t\t\tif _, exists := processFn.ProcessContinuation(); !exists {\n\t\t\t\terr := errors.Errorf(\"missing return value in %v: return value of type %v is not present\",\n\t\t\t\t\tprocessElementName, reflect.TypeOf((*sdf.ProcessContinuation)(nil)).Elem())\n\t\t\t\treturn errors.SetTopLevelMsgf(err, \"Missing output value in method %v, \"+\n\t\t\t\t\t\"%v method should return %v when %v method is defined.\",\n\t\t\t\t\tprocessElementName, processElementName, reflect.TypeOf((*sdf.ProcessContinuation)(nil)).Elem(), truncateRestrictionName)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc sdfRequiredParamStartIndex(method *funcx.Fn) int {\n\tif ctxIndex, ok := method.Context(); ok {\n\t\treturn ctxIndex + 1\n\t}\n\n\treturn 0\n}","sourceCodeStart":1091,"sourceCodeEnd":1127,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/go/pkg/beam/core/graph/fn.go#L1091-L1127","documentation":"When a splittable DoFn defines TruncateRestriction, its ProcessElement must return a sdf.ProcessContinuation as one of its outputs. Beam raises this error if TruncateRestriction exists but ProcessElement has no ProcessContinuation return value, because truncation only makes sense for resumable processing.","triggerScenarios":"Adding a TruncateRestriction method to an SDF whose ProcessElement returns only element outputs (no sdf.ProcessContinuation), then running a pipeline where a splittable element gets truncated (e.g. on drain/failover).","commonSituations":"Retrofitting an existing SDF with truncation support; copying TruncateRestriction from another DoFn without updating ProcessElement's signature.","solutions":["Change ProcessElement to return (your outputs, sdf.ProcessContinuation) and use sdf.ResumeProcessElement or sdf.StopProcessing as appropriate.","If you do not need resumable processing, remove the TruncateRestriction method entirely.","Use beam.Validate/DoFn validation locally by writing a unit test constructing the DoFn with beam.TryCreateDoFn to catch this before pipeline runs."],"exampleFix":"// before\nfunc (fn *f) ProcessElement(rt *sdf.LockRTracker, r rangeT, emit func(int)) {}\n// after\nfunc (fn *f) ProcessElement(rt *sdf.LockRTracker, r rangeT, emit func(int)) sdf.ProcessContinuation {\n    ...\n    return sdf.ResumeProcessElement()\n}","handlingStrategy":"validation","validationCode":"func hasProcessContinuation(fn interface{}) bool {\n    t := reflect.TypeOf(fn)\n    pe, ok := t.MethodByName(\"ProcessElement\")\n    if !ok { return false }\n    pc := reflect.TypeOf((*sdf.ProcessContinuation)(nil)).Elem()\n    for i := 0; i < pe.Type.NumOut(); i++ {\n        if pe.Type.Out(i) == pc { return true }\n    }\n    return false\n}\n// require: hasProcessContinuation(dofn) || !hasTruncateRestriction(dofn)","typeGuard":"func truncateNeedsContinuation(fn interface{}) bool {\n    _, hasTrunc := reflect.TypeOf(fn).MethodByName(\"TruncateRestriction\")\n    return hasTrunc && !hasProcessContinuation(fn) // must be false before submission\n}","tryCatchPattern":null,"preventionTips":["Whenever you add TruncateRestriction, immediately update ProcessElement to return sdf.ProcessContinuation.","Check TruncateRestriction's presence in code review when SDFs change."],"tags":["go","apache-beam","splittable-dofn","process-continuation"],"backgroundTag":"method-signature-mismatch","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-20T03:17:13.778Z"}