{"record":{"id":"7b3849aa6a5e420d","repo":"apache/beam","slug":"error-decoding-append-bag-user-state-window-key-v-v","errorCode":null,"errorMessage":"error decoding append bag user state window key %v: %v","messagePattern":"error decoding append bag user state window key (.+?): (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sdks/go/pkg/beam/runners/prism/internal/engine/data.go","lineNumber":101,"sourceCode":"}\n\n// WriteTimers adds timers to the associated transform handler.\nfunc (d *TentativeData) WriteTimers(transformID, familyID string, timers []byte) {\n\tif d.timers == nil {\n\t\td.timers = map[TimerKey][][]byte{}\n\t}\n\tlink := TimerKey{Transform: transformID, Family: familyID}\n\td.timers[link] = append(d.timers[link], timers)\n}\n\nfunc (d *TentativeData) toWindow(wKey []byte) typex.Window {\n\tif len(wKey) == 0 {\n\t\treturn window.GlobalWindow{}\n\t}\n\t// TODO: Custom Window handling.\n\tw, err := exec.MakeWindowDecoder(coder.NewIntervalWindow()).DecodeSingle(bytes.NewBuffer(wKey))\n\tif err != nil {\n\t\tpanic(fmt.Sprintf(\"error decoding append bag user state window key %v: %v\", wKey, err))\n\t}\n\treturn w\n}\n\n// GetBagState retrieves available state from the tentative bundle data.\n// The stateID has the Transform and Local fields populated, for the Transform and UserStateID respectively.\nfunc (d *TentativeData) GetBagState(stateID LinkID, wKey, uKey []byte) [][]byte {\n\twinMap := d.state[stateID]\n\tw := d.toWindow(wKey)\n\tdata := winMap[w][string(uKey)]\n\tslog.Debug(\"State() Bag.Get\", slog.Any(\"StateID\", stateID), slog.Any(\"UserKey\", uKey), slog.Any(\"Window\", w), slog.Any(\"Data\", data))\n\treturn data.Bag\n}\n\nfunc (d *TentativeData) appendState(stateID LinkID, wKey []byte) map[string]StateData {\n\tif d.state == nil {\n\t\td.state = map[LinkID]map[typex.Window]map[string]StateData{}\n\t}","sourceCodeStart":83,"sourceCodeEnd":119,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/go/pkg/beam/runners/prism/internal/engine/data.go#L83-L119","documentation":"prism converts stored user-state window keys back into window values via an IntervalWindow decoder (toWindow). An empty key means the global window; otherwise the bytes must decode as an interval window. Failure panics because state data written by the SDK cannot be interpreted.","triggerScenarios":"toWindow receives a non-empty wKey byte slice that exec.MakeWindowDecoder(coder.NewIntervalWindow()).DecodeSingle fails on — truncated, corrupt, or non-interval-window encoded bytes in the state key.","commonSituations":"SDK writes custom windows while prism assumes interval windows (see TODO in code); state key corruption; version skew in window encoding between SDK and prism.","solutions":["Avoid custom windowing with user state when using prism (only interval windows supported here)","Verify SDK and prism versions match so window encodings agree","Inspect the wKey bytes in the panic for truncation/corruption","Report the failing pipeline to Beam if a custom window coder should be supported"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"if len(wKey) == 0 { return window.GlobalWindow{} } // caller can pre-check before invoking state APIs\n// and only use interval windows with prism user state","typeGuard":null,"tryCatchPattern":"// toWindow panics; recover only at the state-handling boundary if wrapping prism\ndefer func() { if r := recover(); r != nil { log.Errorf(\"state window key decode failed: %v\", r) } }()","preventionTips":["Use only interval windows with user state on prism","Keep SDK and prism versions aligned","Avoid custom window coders in stateful pipelines until supported"],"tags":["go","beam","prism","state","windowing","panic"],"backgroundTag":"internal-invariant-violation","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}