{"record":{"id":"3af105febfef1e76","repo":"apache/beam","slug":"builddescriptor-invalid-stage-no-transforms-at-all-v","errorCode":null,"errorMessage":"buildDescriptor: invalid stage - no transforms at all %v","messagePattern":"buildDescriptor: invalid stage - no transforms at all (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sdks/go/pkg/beam/runners/prism/internal/stage.go","lineNumber":542,"sourceCode":"\t\t\t\tstg.processingTimeTimers[timerID] = true\n\t\t\t}\n\t\t\trewrite = true\n\t\t\tnewCid, err := lpUnknownCoders(v.GetTimerFamilyCoderId(), coders, comps.GetCoders())\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"unable to rewrite coder %v for timer %v for transform %v in stage %v: %w\", v.GetTimerFamilyCoderId(), timerID, tid, stg.ID, err)\n\t\t\t}\n\t\t\tv.TimerFamilyCoderId = newCid\n\t\t}\n\t\tif rewrite {\n\t\t\tpyld, err := proto.MarshalOptions{}.Marshal(pardo)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"unable to encode ParDoPayload for %v in stage %v after rewrite\", tid, stg.ID)\n\t\t\t}\n\t\t\tt.Spec.Payload = pyld\n\t\t}\n\t}\n\tif len(transforms) == 0 {\n\t\treturn fmt.Errorf(\"buildDescriptor: invalid stage - no transforms at all %v\", stg.ID)\n\t}\n\n\t// Start with outputs, since they're simple and uniform.\n\tsink2Col := map[string]string{}\n\tcol2Coders := map[string]engine.PColInfo{}\n\tfor _, o := range stg.outputs {\n\t\tcol := clonePColToBundle(o.Global)\n\t\twOutCid, err := makeWindowedValueCoder(o.Global, comps, coders)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"buildDescriptor: failed to handle coder on stage %v for output %+v, pcol %q %v:\\n%w %v\", stg.ID, o, o.Global, prototext.Format(col), err, stg.transforms)\n\t\t}\n\t\tsinkID := o.Transform + \"_\" + o.Local\n\t\ted := collectionPullDecoder(col.GetCoderId(), coders, comps)\n\n\t\tvar kd func(io.Reader) []byte\n\t\tif kcid, ok := extractKVCoderID(col.GetCoderId(), coders); ok {\n\t\t\tkd = collectionPullDecoder(kcid, coders, comps)\n\t\t}","sourceCodeStart":524,"sourceCodeEnd":560,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/go/pkg/beam/runners/prism/internal/stage.go#L524-L560","documentation":"buildDescriptor refuses to construct a bundle descriptor for a stage whose transform list is empty. A prism stage must contain at least one pipeline transform to execute; an empty stage means the stage-building logic received no transforms, which is an invalid pipeline partition.","triggerScenarios":"executePipeline produced a stage with zero transforms assigned, then called buildDescriptor on it.","commonSituations":"Runner-side stage-assignment bugs; pipelines with degenerate graph shapes (e.g. transforms all optimized away); custom runner hooks altering stage topology.","solutions":["Log/inspect the stage ID and pipeline graph to see why the stage got no transforms","Check whether a custom optimization or fusion override dropped all transforms","Simplify the pipeline graph to isolate the offending topology","Report to Beam if triggered by a standard pipeline"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Guard: ensure stage has transforms before descriptor build\nif len(stageTransforms) == 0 {\n    return fmt.Errorf(\"stage %s has no transforms; check pipeline plan\", stageID)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Avoid custom graph optimizations that can drop all transforms","Keep runner internals up to date","Validate pipeline graphs with standard runners first"],"tags":["beam","prism","stage","pipeline-graph"],"backgroundTag":"internal-invariant-violation","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"}