apache/beam · error

bad N

Error message

bad N: %v

What it means

EncodeCoderRef serializes a beam coder into its Dataflow-runner representation. A coder.Nullable must have exactly one component (the inner value coder); if it doesn't, the coder is structurally invalid and the library refuses to encode it rather than emit a corrupt CoderRef to the service. The message includes the offending coder for diagnosis.

Solutions

  1. Verify the Nullable coder has exactly one component: len(c.Components) == 1 before serialization.
  2. Build nullable coders with the SDK helpers (e.g. derive them from typex.NullableType typed values) instead of constructing coder.Coder literals manually.
  3. Check the pipeline for custom coders overriding a nullable field and fix the override.
  4. If this arose from re-encoding a decoded CoderRef, confirm encode and decode paths are from the same Beam SDK version.

Example fix

// before
c := &coder.Coder{Kind: coder.Nullable, T: t, Components: nil}
ref, err := graphx.EncodeCoderRef(c)

// after
inner := graphx.InferCoder(typex.New(typex.StringType))
c := &coder.Coder{Kind: coder.Nullable, T: typex.New(typex.NullableType, inner.T), Components: []*coder.Coder{inner}}
ref, err := graphx.EncodeCoderRef(c)
Defensive patterns

Strategy: validation

Validate before calling

func validNullable(c *coder.Coder) bool {
	return c != nil && c.Kind == coder.Nullable && len(c.Components) == 1
}

Type guard

func isCoderOfKind(c *coder.Coder, k coder.Kind) bool { return c != nil && c.Kind == k }

Try / catch

ref, err := graphx.EncodeCoderRef(c)
if err != nil {
	if strings.Contains(err.Error(), "bad N") {
		return fmt.Errorf("nullable coder must have exactly 1 component: %w", err)
	}
	return err
}

Prevention

When it happens

Trigger: Calling EncodeCoderRef (directly or via EncodeCoder/EncodeCoderRefs during pipeline serialization for the Dataflow runner) with a coder.Coder of Kind coder.Nullable whose Components slice has length != 1 (e.g. zero components from a hand-constructed coder, or multiple components from a malformed decode).

Common situations: Hand-building Coder structs instead of using coder.New; a schema/typed pipeline where a nullable field's component failed to attach; decoding a CoderRef from a different Beam version whose component count differs, then re-encoding; custom coder wrappers that mislabel themselves as Nullable.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

Thrown at sdks/go/pkg/beam/core/runtime/graphx/dataflow.go:125

	case coder.KV:
		if len(c.Components) != 2 {
			return nil, errors.Errorf("bad KV: %v", c)
		}

		key, err := EncodeCoderRef(c.Components[0])
		if err != nil {
			return nil, err
		}
		value, err := EncodeCoderRef(c.Components[1])
		if err != nil {
			return nil, err
		}
		return &CoderRef{Type: pairType, Components: []*CoderRef{key, value}, IsPairLike: true}, nil

	case coder.Nullable:
		if len(c.Components) != 1 {
			return nil, errors.Errorf("bad N: %v", c)
		}
		innerref, err := EncodeCoderRef(c.Components[0])
		if err != nil {
			return nil, err
		}
		return &CoderRef{Type: nullableType, Components: []*CoderRef{innerref}}, nil

	case coder.Iterable:
		if len(c.Components) != 1 {
			return nil, errors.Errorf("bad I: %v", c)
		}
		innerref, err := EncodeCoderRef(c.Components[0])
		if err != nil {
			return nil, err
		}
		return &CoderRef{Type: streamType, Components: []*CoderRef{innerref}}, nil

	case coder.CoGBK:

View on GitHub (pinned to 12126d8942)