apache/beam · error

ReadSimpleRowHeader reading nils count: %v, %v

Error message

ReadSimpleRowHeader reading nils count: %v, %v

What it means

ReadSimpleRowHeader decodes a simple row header (field count and nils count) from a Beam row encoding stream. While reading the nils count varint it wraps any decode error in this message. It indicates the byte stream ended prematurely or is corrupted at the position where the nils count should be.

Source

Thrown at sdks/go/pkg/beam/core/graph/coder/row.go:222

	}
	return nil
}

// ReadSimpleRowHeader is a convenience function to read Beam Schema Row Headers
// for values that do not have any nil fields. Reads and validates the number of
// fields total (returning an error for mismatches, and checks that there are
// no nils encoded as a bit field.
func ReadSimpleRowHeader(fields int, r io.Reader) error {
	n, err := DecodeVarInt(r)
	if err != nil {
		return fmt.Errorf("ReadSimpleRowHeader field count: %v, %v", n, err)
	}
	if int(n) != fields {
		return fmt.Errorf("ReadSimpleRowHeader field count mismatch, got %v, want %v", n, fields)
	}
	n, err = DecodeVarInt(r)
	if err != nil {
		return fmt.Errorf("ReadSimpleRowHeader reading nils count: %v, %v", n, err)
	}
	if n != 0 {
		return fmt.Errorf("ReadSimpleRowHeader expected no nils encoded count, got %v", n)
	}
	return nil
}

View on GitHub (pinned to 12126d8942)

Solutions

  1. Verify the byte slice/stream is complete and not truncated before decoding (check you wrote/read the full encoded row).
  2. Ensure encoding and decoding use the same beam SDK version and coder (simple row header format changed across versions).
  3. Check that the reader is positioned at the start of a valid encoded row, not mid-record.
  4. Wrap Decode/Encode calls so partial failures invalidate the whole record instead of resuming mid-stream.

Example fix

// before: decoding a possibly truncated buffer
row, err := dec.Decode(bytes.NewReader(buf[:10]))
// after: validate buffer completeness first
if len(buf) < minHeaderBytes { return fmt.Errorf("buffer too short: %d", len(buf)) }
row, err := dec.Decode(bytes.NewReader(buf))
Defensive patterns

Strategy: try-catch

Validate before calling

if len(buf) < 2 { return fmt.Errorf("encoded row too short: %d bytes", len(buf)) }

Type guard

func isTruncated(err error) bool { return errors.Is(err, io.EOF) || strings.Contains(err.Error(), "reading nils count") }

Try / catch

row, err := dec.Decode(r)
if err != nil {
    if isTruncated(err) { return ErrIncompleteRecord }
    return err
}

Prevention

When it happens

Trigger: Calling ut1Dec / row decoding (e.g. via beam.RowEncoder or exec coders) on a truncated or misaligned byte stream: the field-count varint read succeeded, but the next DecodeVarInt call hit an error (typically io.EOF from a cut-off buffer).

Common situations: Truncated serialized rows from a corrupted data file or pipeline transport; decoding a hand-crafted or older-version byte encoding that lacks the nils count field; incorrect re-use of a decoder across stream boundaries.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


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