{"record":{"id":"92cf223a610c972d","repo":"apache/beam","slug":"unable-to-decode-pardopayload-for-transform-v-handlepardo","errorCode":null,"errorMessage":"unable to decode ParDoPayload for transform[%v]","messagePattern":"unable to decode ParDoPayload for transform\\[(.+?)\\]","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sdks/go/pkg/beam/runners/prism/internal/handlepardo.go","lineNumber":77,"sourceCode":"// PrepareTransform handles special processing with respect to ParDos, since their handling is dependant on supported features\n// and requirements.\nfunc (h *pardo) PrepareTransform(tid string, t *pipepb.PTransform, comps *pipepb.Components) prepareResult {\n\n\t// ParDos are a pain in the butt.\n\t// Combines, by comparison, are dramatically simpler.\n\t// This is because for ParDos, how they are handled, and what kinds of transforms are in\n\t// and around the ParDo, the actual shape of the graph will change.\n\t// At their simplest, it's something a DoFn will handle on their own.\n\t// At their most complex, they require intimate interaction with the subgraph\n\t// bundling process, the data layer, state layers, and control layers.\n\t// But unlike combines, which have a clear urn for composite + special payload,\n\t// ParDos have the standard URN for composites with the standard payload.\n\t// So always, we need to first unmarshal the payload.\n\n\tpardoPayload := t.GetSpec().GetPayload()\n\tpdo := &pipepb.ParDoPayload{}\n\tif err := (proto.UnmarshalOptions{}).Unmarshal(pardoPayload, pdo); err != nil {\n\t\tpanic(fmt.Sprintf(\"unable to decode ParDoPayload for transform[%v]\", t.GetUniqueName()))\n\t}\n\n\t// Lets check for and remove anything that makes things less simple.\n\tif pdo.RestrictionCoderId == \"\" {\n\t\t// Which inputs are Side inputs don't change the graph further,\n\t\t// so they're not included here. Any nearly any ParDo can have them.\n\n\t\t// At their simplest, we don't need to do anything special at pre-processing time, and simply pass through as normal.\n\n\t\t// ForceRoots cause fusion breaks in the optimized graph.\n\t\t// StatefulDoFns need to be marked as being roots, for correct per-key state handling.\n\t\t// Prism already sorts input elements for a stage by EventTime, so a fusion break enables the sorted behavior.\n\t\tvar forcedRoots []string\n\t\tif len(pdo.GetStateSpecs())+len(pdo.GetTimerFamilySpecs()) > 0 ||\n\t\t\tpdo.GetRequiresTimeSortedInput() {\n\t\t\tforcedRoots = append(forcedRoots, tid)\n\t\t}\n","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/go/pkg/beam/runners/prism/internal/handlepardo.go#L59-L95","documentation":"The prism runner's PrepareTransform tries to unmarshal the transform's spec payload into a pipepb.ParDoPayload before handling the ParDo. If the payload bytes cannot be decoded as a ParDoPayload protobuf, the runner panics rather than continuing, because the rest of ParDo handling depends on fields like RestrictionCoderId.","triggerScenarios":"A pipeline is submitted to the prism runner with a transform whose URN is a ParDo URN but whose spec payload is empty, truncated, corrupt, or was serialized by an SDK producing an incompatible/older ParDoPayload encoding.","commonSituations":"Running a pipeline with an SDK/runner version mismatch where the protobuf definitions diverged; a custom or hand-crafted pipeline graph (e.g. from a test harness or job-submission tool) that sets a wrong payload for a ParDo transform.","solutions":["Verify the SDK and prism runner versions come from the same Beam release so the ParDoPayload proto matches.","Inspect the failing transform's URN and spec payload (prototext/protoc) to confirm it is a well-formed ParDoPayload.","Rebuild/regenerate the pipeline so the ParDo spec payload is populated by the SDK's standard transform-creation path, not hand-constructed.","If it persists, file a Beam issue with the pipeline graph dump; this is normally an SDK-side serialization bug."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"if t.GetSpec().GetUrn() == urns.TransformParDo && len(t.GetSpec().GetPayload()) == 0 {\n    // skip/submit error before invoking prism\n}\npdo := &pipepb.ParDoPayload{}\nif err := proto.Unmarshal(t.GetSpec().GetPayload(), pdo); err != nil { /* handle */ }","typeGuard":"func isDecodableParDo(t *pipepb.PTransform) bool { p := t.GetSpec().GetPayload(); return p != nil && t.GetSpec().GetUrn() == urns.TransformParDo }","tryCatchPattern":"defer func(){ if r := recover(); r != nil && strings.Contains(fmt.Sprint(r), \"unable to decode ParDoPayload\") { /* handle submit failure */ } }()","preventionTips":["Keep SDK and prism runner on the same Beam release","Never hand-construct ParDo spec payloads; use the SDK transform APIs","Dump and protoc-decode failing payloads when diagnosing"],"tags":["go","protobuf","apache-beam","runner"],"backgroundTag":"protobuf-unmarshal-failed","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"}