apache/beam · critical
unable to decode bool; expected
Error message
unable to decode bool; expected {0, 1} got %v What it means
decoder.Bool in the prism runner's engine decodes a single byte as a boolean, accepting only 0 (false) and 1 (true). Any other byte value means the byte stream is corrupted or misaligned relative to the coder that produced it, so the decoder panics rather than silently returning a wrong value.
Solutions
- Verify the coder registered for the PCollection actually matches the bytes being produced (re-check the pipeline's coder inference).
- Ensure both producer and consumer use the same Beam SDK version so bool coders agree on the {0,1} encoding.
- Dump the raw bytes around the failure to find the misalignment point and fix the coder that wrote the extra/mis-sized field.
- If using custom coders, emit bools strictly as single bytes 0 or 1.
Example fix
// before (custom coder writing Go bool's textual form)
w.Write([]byte(fmt.Sprintf("%v", value))) // writes "true" -> first byte 't' panics
// after
if value { w.Write([]byte{1}) } else { w.Write([]byte{0}) } Defensive patterns
Strategy: validation
Validate before calling
// Validate the encoded byte stream before handing it to the runner
func validateBoolBytes(data []byte) error {
for i, b := range data {
if b != 0 && b != 1 {
return fmt.Errorf("byte at %d is %d, not a valid bool encoding", i, b)
}
}
return nil
} Type guard
func isBoolByte(b byte) bool { return b == 0 || b == 1 } Prevention
- Keep producer and consumer Beam SDK versions in sync
- Never hand-roll bool encoding in custom coders; use the SDK's coder utilities
- Validate raw element bytes when debugging cross-language pipelines
When it happens
Trigger: A encoded data stream (e.g. element or timer blobs from the FnAPI) contains a byte other than 0 or 1 at a position where the coder says a bool should be; typically a decoder misalignment after a previous field was read with the wrong width, or a custom/unknown coder emitting non-standard bool encodings.
Common situations: Mismatched coder versions between SDK language SDKs and prism, a hand-written coder emitting true/false as arbitrary bytes, or byte-stream corruption when elements are passed between runner stages.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/a00d413b9ad6f097.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/go/pkg/beam/runners/prism/internal/engine/timers.go:239
b := d.raw[d.cursor:end]
d.cursor = end
return b
}
// UnusedBytes returns the remainder of bytes in the buffer that weren't yet used.
// Multiple timers can be provided in a single timers buffer, since multiple dynamic
// timer tags may be set.
func (d *decoder) UnusedBytes() []byte {
return d.raw[d.cursor:]
}
func (d *decoder) Bool() bool {
if b := d.Byte(); b == 0 {
return false
} else if b == 1 {
return true
} else {
panic(fmt.Sprintf("unable to decode bool; expected {0, 1} got %v", b))
}
}
func (d *decoder) Pane() typex.PaneInfo {
first := d.Byte()
pn := coder.NewPane(first & 0x0f)
switch first >> 4 {
case 0:
// Result encoded in only one pane.
return pn
case 1:
// Result encoded in one pane plus a VarInt encoded integer.
index := d.Varint()
pn.Index = index
if pn.Timing == typex.PaneEarly {
pn.NonSpeculativeIndex = -1
} else {View on GitHub (pinned to 12126d8942)