{"record":{"id":"249e579f0b1f5f95","repo":"apache/beam","slug":"panic-formatpardoerror-dofn-len-ret-1","errorCode":null,"errorMessage":"panic(formatParDoError(dofn, len(ret), 1))","messagePattern":"panic\\(formatParDoError\\(dofn, len\\(ret\\), 1\\)\\)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sdks/go/pkg/beam/pardo.go","lineNumber":431,"sourceCode":"// one between a producer ParDo and a consumer ParDo), the PCollection itself\n// is \"fused away\" and won't ever be written to disk, saving all the I/O and\n// space expense of constructing it.\n//\n// When Beam runners apply fusion optimization, it is essentially \"free\" to\n// write ParDo operations in a very modular, composable style, each ParDo\n// operation doing one clear task, and stringing together sequences of ParDo\n// operations to get the desired overall effect. Such programs can be easier to\n// understand, easier to unit-test, easier to extend and evolve, and easier to\n// reuse in new programs. The predefined library of PTransforms that come with\n// Beam makes heavy use of this modular, composable style, trusting to the\n// runner to \"flatten out\" all the compositions into highly optimized stages.\n//\n// See https://beam.apache.org/documentation/programming-guide/#pardo\n// for the web documentation for ParDo\nfunc ParDo(s Scope, dofn any, col PCollection, opts ...Option) PCollection {\n\tret := MustN(TryParDo(s, dofn, col, opts...))\n\tif len(ret) != 1 {\n\t\tpanic(formatParDoError(dofn, len(ret), 1))\n\t}\n\treturn ret[0]\n}\n\n// TODO(herohde) 6/1/2017: add windowing aspects to above documentation.\n\n// ParDo2 inserts a ParDo with 2 outputs into the pipeline.\nfunc ParDo2(s Scope, dofn any, col PCollection, opts ...Option) (PCollection, PCollection) {\n\tret := MustN(TryParDo(s, dofn, col, opts...))\n\tif len(ret) != 2 {\n\t\tpanic(formatParDoError(dofn, len(ret), 2))\n\t}\n\treturn ret[0], ret[1]\n}\n\n// ParDo3 inserts a ParDo with 3 outputs into the pipeline.\nfunc ParDo3(s Scope, dofn any, col PCollection, opts ...Option) (PCollection, PCollection, PCollection) {\n\tret := MustN(TryParDo(s, dofn, col, opts...))","sourceCodeStart":413,"sourceCodeEnd":449,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/go/pkg/beam/pardo.go#L413-L449","documentation":"ParDo applies a ParDo transform that must produce exactly one output PCollection. If TryParDo returns a number of PCollections other than 1, it panics with a formatted ParDo error naming the dofn, actual count, and expected count of 1.","triggerScenarios":"Calling beam.ParDo with a DoFn that returns zero values (side-effect only) or multiple outputs (e.g. (string, int) or ProcessElement with multiple emitters).","commonSituations":"Using a multi-output DoFn (written for ParDo2/ParDo3) with ParDo, or a sink-style DoFn with no returns passed to ParDo after a refactor.","solutions":["Ensure the DoFn's ProcessElement returns exactly one output value (plus optional error per Beam Go conventions)","Use ParDo0 for no-output DoFns or ParDo2/ParDo3... for multi-output DoFns","Read formatParDoError's message to see the actual vs expected count and adjust accordingly"],"exampleFix":"// before\nbeam.ParDo(s, func(x int, emit func(int), emit2 func(int)) {...}, col) // 2 outputs\n// after\no1, o2 := beam.ParDo2(s, func(x int, emit func(int), emit2 func(int)) {...}, col)","handlingStrategy":"type-guard","validationCode":"// A ParDo DoFn must produce exactly one output per element","typeGuard":"func isSingleOutputDoFn(fn any) bool {\n    t := reflect.TypeOf(fn)\n    for t.Kind() == reflect.Ptr {\n        t = t.Elem()\n    }\n    m, ok := t.MethodByName(\"ProcessElement\")\n    if !ok { return false }\n    // heuristic: exactly one emit param or one non-error return value\n    numEmit := 0\n    for i := 0; i < m.Type.NumIn(); i++ {\n        if m.Type.In(i).Kind() == reflect.Func { numEmit++ }\n    }\n    return numEmit == 1 || (m.Type.NumOut() == 1)\n}","tryCatchPattern":"defer func() {\n    if r := recover(); r != nil {\n        err = fmt.Errorf(\"ParDo arity mismatch: %v\", r)\n    }\n}()","preventionTips":["Use ParDo only for single-output DoFns; switch to ParDo2/ParDo3 for multi-output","Keep DoFn signatures stable or update all apply call sites together","Rely on formatParDoError's message to identify the actual output count"],"tags":["go","beam","pardo","arity"],"backgroundTag":"unexpected-response-shape","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"}