apache/beam · error
expected WV coder for user state
Error message
expected WV coder for user state %v: %v
What it means
NewUserStateAdapter builds a state adapter for Beam Go user state. The runner protocol requires state coders to carry windowing information, so the coder must be a W<V> or W<KV<K,V>> wrapper. If coder.IsW(c) is false, the library panics because state without window encoding cannot round-trip correctly.
Solutions
- Wrap the coder with coder.NewW(valueCoder) before passing it to NewUserStateAdapter
- Verify with coder.IsW(c) and inspect coder.SkipW(c) to confirm the inner coder is V or KV<K,V>
- Ensure the pipeline graph is built via the standard graphx/translate path, which applies window wrapping automatically
Example fix
// before exec.NewUserStateAdapter(sid, kvCoder, ...) // after exec.NewUserStateAdapter(sid, coder.NewW(kvCoder), ...)
Defensive patterns
Strategy: validation
Validate before calling
if !coder.IsW(c) { return fmt.Errorf("state coder must be windowed: %v", c) }
exec.NewUserStateAdapter(sid, c, ...) Type guard
func isWindowedCoder(c *coder.Coder) bool { return coder.IsW(c) } Try / catch
defer func() { if r := recover(); r != nil { err = fmt.Errorf("user state adapter: %v", r) } }() Prevention
- Always wrap state coders with coder.NewW
- Assert coder.IsW in unit tests around state adapters
- Let the standard translate pipeline construct coders
When it happens
Trigger: Calling exec.NewUserStateAdapter with a coder that is not a windowed coder (e.g. a plain V or KV<K,V> coder) instead of coder.NewW(...) of the value coder.
Common situations: Constructing state adapters manually in custom runners or tests; passing a coder produced by graphx without wrapping; migrating pipelines between SDK versions where state coder wrapping conventions changed.
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/7f204a52925f2a4c.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/go/pkg/beam/core/runtime/exec/userstate.go:648
type UserStateAdapter interface {
NewStateProvider(ctx context.Context, reader StateReader, w typex.Window, element any) (stateProvider, error)
}
type userStateAdapter struct {
sid StreamID
wc WindowEncoder
kc ElementEncoder
stateIDToCoder map[string]*coder.Coder
stateIDToKeyCoder map[string]*coder.Coder
stateIDToCombineFn map[string]*graph.CombineFn
c *coder.Coder
}
// NewUserStateAdapter returns a user state adapter for the given StreamID and coder.
// It expects a W<V> or W<KV<K,V>> coder, because the protocol requires windowing information.
func NewUserStateAdapter(sid StreamID, c *coder.Coder, stateIDToCoder map[string]*coder.Coder, stateIDToKeyCoder map[string]*coder.Coder, stateIDToCombineFn map[string]*graph.CombineFn) UserStateAdapter {
if !coder.IsW(c) {
panic(fmt.Sprintf("expected WV coder for user state %v: %v", sid, c))
}
wc := MakeWindowEncoder(c.Window)
var kc ElementEncoder
if coder.IsKV(coder.SkipW(c)) {
kc = MakeElementEncoder(coder.SkipW(c).Components[0])
}
return &userStateAdapter{sid: sid, wc: wc, kc: kc, c: c, stateIDToCoder: stateIDToCoder, stateIDToKeyCoder: stateIDToKeyCoder, stateIDToCombineFn: stateIDToCombineFn}
}
// NewStateProvider creates a stateProvider with the ability to talk to the state API.
func (s *userStateAdapter) NewStateProvider(ctx context.Context, reader StateReader, w typex.Window, element any) (stateProvider, error) {
if s.kc == nil {
return stateProvider{}, fmt.Errorf("cannot make a state provider for an unkeyed input %v", element)
}
elementKey, err := EncodeElement(s.kc, element.(*MainInput).Key.Elm)
if err != nil {
return stateProvider{}, errView on GitHub (pinned to 12126d8942)