{"record":{"id":"bd9c4d705134e8c0","repo":"apache/beam","slug":"number-of-emits-in-method-v-does-not-match-method-v-got-d","errorCode":null,"errorMessage":"number of emits in method %v does not match method %v: got %d, expected %d","messagePattern":"number of emits in method (.+?) does not match method (.+?): got (.+?), expected (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sdks/go/pkg/beam/core/graph/fn.go","lineNumber":713,"sourceCode":"\tposMethodEmits, numMethodEmits, ok := method.Emits()\n\tnumProcessEmits := len(processFnEmits)\n\n\t// Handle cases where method has no emits.\n\tif !ok {\n\t\tif numProcessEmits == 0 { // We're good, expected no emits.\n\t\t\treturn nil\n\t\t}\n\t\t// Error, missing emits.\n\t\terr := errors.Errorf(\"emit parameters expected in method %v\", methodName)\n\t\treturn errors.SetTopLevelMsgf(err,\n\t\t\t\"Missing emit parameters in the %v method of a DoFn. \"+\n\t\t\t\t\"If emit parameters are present in %v those parameters must also be present in %v.\",\n\t\t\tmethodName, processElementName, methodName)\n\t}\n\n\t// Error if number of emits doesn't match.\n\tif numMethodEmits != numProcessEmits {\n\t\terr := errors.Errorf(\"number of emits in method %v does not match method %v: got %d, expected %d\",\n\t\t\tmethodName, processElementName, numMethodEmits, numProcessEmits)\n\t\treturn errors.SetTopLevelMsgf(err,\n\t\t\t\"Incorrect number of emit parameters in the %v method of a DoFn. \"+\n\t\t\t\t\"The emit parameters should match those of the %v method.\",\n\t\t\tmethodName, processElementName)\n\t}\n\n\t// Error if there's a type mismatch.\n\tmethodEmits := method.Param[posMethodEmits : posMethodEmits+numMethodEmits]\n\tfor i := 0; i < numProcessEmits; i++ {\n\t\tif processFnEmits[i].T != methodEmits[i].T {\n\t\t\tvar err error = &funcx.TypeMismatchError{Got: methodEmits[i].T, Want: processFnEmits[i].T}\n\t\t\terr = errors.Wrapf(err, \"emit parameter in method %v does not match emit parameter in %v\",\n\t\t\t\tmethodName, processElementName)\n\t\t\treturn errors.SetTopLevelMsgf(err,\n\t\t\t\t\"Incorrect emit parameters in the %v method of a DoFn. \"+\n\t\t\t\t\t\"The emit parameters should match those of the %v method.\",\n\t\t\t\tmethodName, processElementName)","sourceCodeStart":695,"sourceCodeEnd":731,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/go/pkg/beam/core/graph/fn.go#L695-L731","documentation":"Apache Beam Go validates optional DoFn methods (e.g. StartBundle, FinishBundle, Setup, Teardown) against ProcessElement. When such a method declares emit (PCollection output) parameters, their count must exactly match the number of emits in ProcessElement. This error is thrown by validateEmits, called from AsDoFn during graph construction, when the counts differ.","triggerScenarios":"Registering a DoFn whose StartBundle/FinishBundle/Setup/Teardown method declares a different number of emit parameters than ProcessElement, then calling beam.ParDo / beam.DoFn conversion (AsDoFn) via beam.ParDo(s, fn, input) when building a pipeline.","commonSituations":"Adding a new output PCollection to ProcessElement but forgetting to add the matching emitter to StartBundle/FinishBundle; copy-pasting a DoFn and editing only ProcessElement; refactoring output counts without updating auxiliary methods.","solutions":["Add or remove emit parameters in the auxiliary method so its emit count matches ProcessElement.","If the method does not need to emit, remove all emit parameters from it.","Use the same emitter types (funcx.OutputT / beam emitter types) as in ProcessElement to also satisfy the follow-up type check (error 4901)."],"exampleFix":"// before\nfunc (fn *myFn) ProcessElement(ctx context.Context, w string, emit1, emit2 func(int)) {}\nfunc (fn *myFn) FinishBundle(emit func(int)) {}\n\n// after\nfunc (fn *myFn) ProcessElement(ctx context.Context, w string, emit1, emit2 func(int)) {}\nfunc (fn *myFn) FinishBundle(emit1, emit2 func(int)) {}","handlingStrategy":"validation","validationCode":"pe := reflect.TypeOf(fn).Method; // compare emitter counts across DoFn methods before beam.ParDo\n// simplest: keep emit parameters only in ProcessElement unless all methods mirror them exactly\nif !dofnEmitsMatch(fn) {\n\treturn fmt.Errorf(\"emit counts must match across DoFn methods\")\n}","typeGuard":"func hasEmits(m reflect.Method) bool { _, ok := m.Type.In(m.Type.NumIn()-1).(interface{}); return ok } // inspect last params for func(...) emitters","tryCatchPattern":"err := beam.ParDo(s, &myFn{}, in); if err != nil {\n\tvar top = errors.UnwrapTop(err)\n\tlog.Fatalf(\"DoFn emit signature invalid: %v\", top)\n}","preventionTips":["Mirror emitter parameters across all DoFn methods by copy-pasting from ProcessElement","Run pipeline construction in a fast unit test before deployment","Avoid declaring emitters in StartBundle/FinishBundle unless actively emitting there"],"tags":["go","apache-beam","dofn","signature-validation","pipeline-construction"],"backgroundTag":"schema-validation-failed","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}