{"record":{"id":"a2e0fbca0f24706a","repo":"apache/beam","slug":"nullable-coder-must-have-only-one-component-s","errorCode":null,"errorMessage":"Nullable coder must have only one component: %s","messagePattern":"Nullable coder must have only one component: (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sdks/go/pkg/beam/runners/prism/internal/coders.go","lineNumber":309,"sourceCode":"\t}\n}\n\n// pullDecoderNoAlloc returns a function that decodes a single element of the given coder.\n// Intended to only be used as an internal function for pullDecoder, which will use a io.TeeReader\n// to extract the bytes.\nfunc pullDecoderNoAlloc(c *pipepb.Coder, coders map[string]*pipepb.Coder) func(io.Reader) {\n\turn := c.GetSpec().GetUrn()\n\tswitch urn {\n\t// Anything length prefixed can be treated as opaque.\n\tcase urns.CoderBytes, urns.CoderStringUTF8, urns.CoderLengthPrefix:\n\t\treturn func(r io.Reader) {\n\t\t\tl, _ := coder.DecodeVarInt(r)\n\t\t\tioutilx.ReadN(r, int(l))\n\t\t}\n\tcase urns.CoderNullable:\n\t\tccids := c.GetComponentCoderIds()\n\t\tif len(ccids) != 1 {\n\t\t\tpanic(fmt.Sprintf(\"Nullable coder must have only one component: %s\", prototext.Format(c)))\n\t\t}\n\t\ted := pullDecoderNoAlloc(coders[ccids[0]], coders)\n\t\treturn func(r io.Reader) {\n\t\t\tb, _ := ioutilx.ReadN(r, 1)\n\t\t\tif len(b) == 0 {\n\t\t\t\treturn\n\t\t\t}\n\t\t\t// Nullable coder is prefixed with 0 or 1 to indicate whether there exists remaining data.\n\t\t\tprefix := b[0]\n\t\t\tif prefix == 0 {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ted(r)\n\t\t}\n\tcase urns.CoderVarInt:\n\t\treturn func(r io.Reader) {\n\t\t\tcoder.DecodeVarInt(r)\n\t\t}","sourceCodeStart":291,"sourceCodeEnd":327,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/go/pkg/beam/runners/prism/internal/coders.go#L291-L327","documentation":"Error returned by the Prism runner's pullDecoderNoAlloc when a nullable coder's component list does not contain exactly one entry. Nullable coders wrap a single inner element coder; any other component count means the coder proto coming from the pipeline is malformed, and the message prints the offending coder for inspection.","triggerScenarios":"A pipeline contains a beam:coder:nullable:v1 coder whose component list is empty or has more than one component coder ID, decoded when prism builds stream decoders.","commonSituations":"Malformed pipeline protos from other SDK versions or third-party tools emitting non-conforming Nullable coders; hand-constructed coder payloads in tests.","solutions":["Fix the pipeline so the Nullable coder declares exactly one component coder ID","Upgrade the producing SDK to a version emitting spec-compliant Nullable coders","Inspect the formatted coder in the panic message (prototext) to see the offending component list","If generated by custom code, correct the coder construction to wrap a single component"],"exampleFix":"// before\n&pipepb.Coder{Spec: nullableUrn, ComponentCoderIds: []string{}},\n// after\n&pipepb.Coder{Spec: nullableUrn, ComponentCoderIds: []string{\"c0\"}},","handlingStrategy":"validation","validationCode":"if c.GetSpec().GetUrn() == \"beam:coder:nullable:v1\" && len(c.GetComponentCoderIds()) != 1 {\n    return fmt.Errorf(\"invalid nullable coder: %v\", c)\n}","typeGuard":null,"tryCatchPattern":"defer func() {\n    if r := recover(); r != nil && strings.Contains(fmt.Sprint(r), \"Nullable coder must have only one component\") {\n        err = fmt.Errorf(\"malformed nullable coder in pipeline: %v\", r)\n    }\n}()","preventionTips":["Emit Nullable coders with exactly one component","Regenerate pipelines with a current Beam SDK","Validate coder component counts before job submission","Inspect prototext dumps when coders come from external tools"],"tags":["prism","coders","validation"],"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-20T03:17:13.778Z"}