apache/beam · error

error encoding pane %v: non-speculative index value must be

Error message

error encoding pane %v: non-speculative index value must be equal to -1 if the pane timing is early

What it means

EncodePane validates pane metadata before encoding: when the pane timing is typex.PaneEarly, the NonSpeculativeIndex must be exactly -1 (the sentinel for 'no speculative index'). This error means a typex.PaneInfo value violates that invariant, so the coder refuses to serialize it rather than producing a corrupt stream.

Source

Thrown at sdks/go/pkg/beam/core/graph/coder/panes.go:47

	pane := byte(0)
	if v.IsFirst {
		pane |= 0x01
	}
	if v.IsLast {
		pane |= 0x02
	}
	pane |= byte(v.Timing << 2)

	switch {
	case (v.Index == 0 && v.NonSpeculativeIndex == 0) || v.Timing == typex.PaneUnknown:
		// The entire pane info is encoded as a single byte
		paneByte := []byte{pane}
		w.Write(paneByte)
	case v.Index == v.NonSpeculativeIndex || v.Timing == typex.PaneEarly:
		// The pane info is encoded as this byte plus a single VarInt encoded integer
		if v.Timing == typex.PaneEarly && v.NonSpeculativeIndex != -1 {
			return fmt.Errorf("error encoding pane %v: non-speculative index value must be equal to -1 if the pane timing is early", v)
		}
		paneByte := []byte{pane | 1<<4}
		w.Write(paneByte)
		EncodeVarInt(v.Index, w)
	default:
		// The pane info is encoded as this byte plus two VarInt encoded integer
		paneByte := []byte{pane | 2<<4}
		w.Write(paneByte)
		EncodeVarInt(v.Index, w)
		EncodeVarInt(v.NonSpeculativeIndex, w)
	}
	return nil
}

// NewPane initializes the PaneInfo from a given byte.
// By default, PaneInfo is assigned to NoFiringPane.
func NewPane(b byte) typex.PaneInfo {
	pn := typex.NoFiringPane()

View on GitHub (pinned to 12126d8942)

Solutions

  1. Set NonSpeculativeIndex to -1 when creating PaneInfo values with Timing == PaneEarly.
  2. Use typex.PaneInfo constructors/helpers instead of struct literals so invariants hold.
  3. Audit custom runner/transform code that builds panes and reset the index for early panes.
  4. If this arises from the Beam runtime itself, file an issue with the Beam Go SDK with the pane value.

Example fix

// before
p := typex.PaneInfo{Timing: typex.PaneEarly, Index: 0, NonSpeculativeIndex: 0}
// after
p := typex.PaneInfo{Timing: typex.PaneEarly, Index: 0, NonSpeculativeIndex: -1}
Defensive patterns

Strategy: validation

Validate before calling

func validPane(p typex.PaneInfo) bool {
	return p.Timing != typex.PaneEarly || p.NonSpeculativeIndex == -1
}

Type guard

func isEarlyPaneValid(p typex.PaneInfo) bool { return p.Timing != typex.PaneEarly || p.NonSpeculativeIndex == -1 }

Try / catch

if err := panes.EncodePane(p, w); err != nil {
	if strings.Contains(err.Error(), "non-speculative index") { log.Printf("invalid pane %v", p) }
	return err
}

Prevention

When it happens

Trigger: Constructing a typex.PaneInfo with Timing set to PaneEarly but NonSpeculativeIndex set to something other than -1, then calling panes.EncodePane (directly or via Encode/EncodeWindowedValueHeader/timer encoding paths).

Common situations: Custom pane bookkeeping in a runner or transform that tracks speculative indexes while also marking early panes; hand-built PaneInfo in tests; a runner bug emitting panes with default 0 index on early firings.

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/dfa1ca394da60bae. Report an issue: GitHub.