jackc/pgx · error
insufficient bytes
Error message
insufficient bytes
What it means
ErrInsufficientBytes is the sentinel (internal/pgio/read.go:12) wrapped by every bounds-check failure in the pgio.Reader — a fixed-size read (Byte/Uint16/…/Int64), Bytes(n), CString (unterminated), or Count (count exceeds remaining) tried to advance past the end of the source byte slice. It surfaces from a pgtype Codec decoding a PostgreSQL binary value whose wire bytes are shorter than the type's layout requires.
Source
Thrown at internal/pgio/read.go:12
package pgio
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
)
// ErrInsufficientBytes is wrapped by all Reader errors caused by a read past
// the end of the source.
var ErrInsufficientBytes = errors.New("insufficient bytes")
// Reader is a bounds-checked reader for the PostgreSQL binary format. It is
// designed so that decoders of untrusted input cannot forget a length check:
// every read validates against the remaining bytes, and the first failure
// sticks. After a failure all subsequent reads return zero values, so a
// decoder can read an entire structure without intermediate error checks and
// inspect Err or Finish once at the end.
//
// Reads never panic. A decoder that branches on a value it just read (e.g. an
// element count used to size an allocation) should check Err before acting on
// the value.
type Reader struct {
s []byte
rp int
err error
}
func NewReader(s []byte) *Reader {View on GitHub (pinned to ec1a0befd2)
Solutions
- If it reproduces on a specific column, capture the raw bytes and confirm the server is sending the documented binary format for that type OID.
- Update pgx and any pgtype-related extensions to match the PostgreSQL server version (codec/server version skew is the most common cause).
- For custom codecs, audit reads to match the documented layout; prefer pgio.Reader over manual slicing so bounds are checked.
- Check the column's typname/typreceive to ensure you are using the right codec; register the correct type if a default fallback is mis-decoding.
- Inspect network/proxy (PgBouncer in non-session-pooling modes, a truncating proxy) if the bytes arrive short.
Example fix
// before (custom codec over-reading)
func (c *MyCodec) DecodeBinary(m *pgtype.Map, src []byte) (any, error) {
return binary.BigEndian.Uint32(src[:4]), nil // panics or wrong if src<4
}
// after — use pgio.Reader, surface ErrInsufficientBytes cleanly
func (c *MyCodec) DecodeBinary(m *pgtype.Map, src []byte) (any, error) {
r := pgio.NewReader(src)
v := r.Uint32()
return v, r.Err()
} Defensive patterns
Strategy: try-catch
Type guard
func isInsufficientBytes(err error) bool { return errors.Is(err, pgio.ErrInsufficientBytes) } Try / catch
v, err := codec.DecodeBinary(typeMap, src)
if errors.Is(err, pgio.ErrInsufficientBytes) {
// truncated/corrupt payload; log OID + len(src) and drop/skip
log.Printf("short binary payload for oid=%d len=%d", oid, len(src))
return nil, err
} Prevention
- Keep pgx and type-extension versions aligned with the server.
- Prefer pgio.Reader in custom codecs so bounds are checked.
- Inspect corrupt OIDs/columns to pinpoint codec/server skew.
- Rule out truncating proxies (PgBouncer, custom middleware).
When it happens
Trigger: Decoding a binary-format value whose payload is truncated: a corrupted/too-short binary column, a server/extension sending malformed data, a codec reading a field the message did not include, or a hand-rolled codec that over-reads. Also from CString on a non-NUL-terminated string.
Common situations: A column of a custom or extension type whose binary format pgx's codec parses incorrectly (version skew); a network/proxy truncating messages; a corrupted pg_dump/restore; an extension returning an unexpected payload shape; a hand-written Codec that mis-sizes reads.
Related errors
AI-assisted analysis of jackc/pgx@ec1a0befd2 (2026-08-04).
Data as JSON: /data/errors/5b79d03c63bd8fa9.json.
Report an issue: GitHub.