apache/beam · error

Nullable coder must have only one component

Error message

Nullable coder must have only one component: %s

What it means

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.

Solutions

  1. Fix the pipeline so the Nullable coder declares exactly one component coder ID
  2. Upgrade the producing SDK to a version emitting spec-compliant Nullable coders
  3. Inspect the formatted coder in the panic message (prototext) to see the offending component list
  4. If generated by custom code, correct the coder construction to wrap a single component

Example fix

// before
&pipepb.Coder{Spec: nullableUrn, ComponentCoderIds: []string{}},
// after
&pipepb.Coder{Spec: nullableUrn, ComponentCoderIds: []string{"c0"}},
Defensive patterns

Strategy: validation

Validate before calling

if c.GetSpec().GetUrn() == "beam:coder:nullable:v1" && len(c.GetComponentCoderIds()) != 1 {
    return fmt.Errorf("invalid nullable coder: %v", c)
}

Try / catch

defer func() {
    if r := recover(); r != nil && strings.Contains(fmt.Sprint(r), "Nullable coder must have only one component") {
        err = fmt.Errorf("malformed nullable coder in pipeline: %v", r)
    }
}()

Prevention

When it happens

Trigger: 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.

Common situations: Malformed pipeline protos from other SDK versions or third-party tools emitting non-conforming Nullable coders; hand-constructed coder payloads in tests.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of apache/beam@12126d8942 (2026-09-13). Data as JSON: /api/errors/a2e0fbca0f24706a. Report an issue: GitHub.

Appendix: source

Thrown at sdks/go/pkg/beam/runners/prism/internal/coders.go:309

	}
}

// pullDecoderNoAlloc returns a function that decodes a single element of the given coder.
// Intended to only be used as an internal function for pullDecoder, which will use a io.TeeReader
// to extract the bytes.
func pullDecoderNoAlloc(c *pipepb.Coder, coders map[string]*pipepb.Coder) func(io.Reader) {
	urn := c.GetSpec().GetUrn()
	switch urn {
	// Anything length prefixed can be treated as opaque.
	case urns.CoderBytes, urns.CoderStringUTF8, urns.CoderLengthPrefix:
		return func(r io.Reader) {
			l, _ := coder.DecodeVarInt(r)
			ioutilx.ReadN(r, int(l))
		}
	case urns.CoderNullable:
		ccids := c.GetComponentCoderIds()
		if len(ccids) != 1 {
			panic(fmt.Sprintf("Nullable coder must have only one component: %s", prototext.Format(c)))
		}
		ed := pullDecoderNoAlloc(coders[ccids[0]], coders)
		return func(r io.Reader) {
			b, _ := ioutilx.ReadN(r, 1)
			if len(b) == 0 {
				return
			}
			// Nullable coder is prefixed with 0 or 1 to indicate whether there exists remaining data.
			prefix := b[0]
			if prefix == 0 {
				return
			}
			ed(r)
		}
	case urns.CoderVarInt:
		return func(r io.Reader) {
			coder.DecodeVarInt(r)
		}

View on GitHub (pinned to 12126d8942)