{"id":"66dc66e4a2e31780","repo":"jackc/pgx","slug":"invalid-length","errorCode":null,"errorMessage":"invalid length","messagePattern":"invalid length","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/pgio/read.go","lineNumber":213,"sourceCode":"// Finish returns the first error encountered, or an error if unread bytes\n// remain. Decoders that must consume the entire source should end with Finish.\nfunc (r *Reader) Finish() error {\n\tif r.err != nil {\n\t\treturn r.err\n\t}\n\tif r.rp != len(r.s) {\n\t\treturn r.errTrailing()\n\t}\n\treturn nil\n}\n\nfunc (r *Reader) errTrailing() error {\n\treturn fmt.Errorf(\"%d unexpected trailing bytes at offset %d\", len(r.s)-r.rp, r.rp)\n}\n\n// ErrInvalidLength is wrapped by the errors returned from the exact-length\n// read functions below.\nvar ErrInvalidLength = errors.New(\"invalid length\")\n\nfunc errLength(want, got int) error {\n\treturn fmt.Errorf(\"%w: expected %d bytes, got %d\", ErrInvalidLength, want, got)\n}\n\n// The Uint*Exact functions read a single fixed-size value that makes up an\n// entire message, which is what the scan plans for the fixed-size PostgreSQL\n// types receive. They are the counterpart to Reader for values that have no\n// internal structure: there is no position to track and no error to make\n// sticky, just an exact-length assertion the caller cannot skip. Keeping them\n// separate from Reader is deliberate — these are the hottest decode paths in\n// the driver and they are small enough for the compiler to inline, which a\n// Reader method carrying a bounds check and a read pointer is not.\n\n// Uint16Exact returns the big-endian uint16 in src, which must be exactly 2 bytes.\nfunc Uint16Exact(src []byte) (uint16, error) {\n\tif len(src) != 2 {\n\t\treturn 0, errLength(2, len(src))","sourceCodeStart":195,"sourceCodeEnd":231,"githubUrl":"https://github.com/jackc/pgx/blob/ec1a0befd22592cffffdeeb0a50311b506372f4c/internal/pgio/read.go#L195-L231","documentation":"ErrInvalidLength is the sentinel (internal/pgio/read.go:213) wrapped by the Uint16Exact/Uint32Exact/Uint64Exact helpers when src is not exactly 2/4/8 bytes. These helpers are the scan plans for fixed-size built-in types (int2/int4/int8/float4/float8 and friends); they assert the server's binary payload length matches the type size, since for an unstructured scalar there is nothing else to check.","triggerScenarios":"Scanning a fixed-size scalar column whose binary representation arrived with the wrong byte length: e.g. an int4 column with a 3- or 8-byte payload, or NULL handled incorrectly so an empty/foreign slice is passed to the Exact helper.","commonSituations":"Server/extension bug returning a wrong-length payload; a codec/type-map misregistration pointing an OID at the wrong Exact helper (e.g. int8 OID mapped to Uint32Exact); corrupted bytes from a proxy; misuse of a custom Codec that forwards the wrong src.","solutions":["Confirm the column type OID is mapped to the correct codec in your TypeMap (a wrong OID→codec mapping produces wrong-length reads).","Capture the failing column's typname and the raw src length to confirm the server payload is genuinely mis-sized.","Update pgx to a release matching your server version.","For custom scalars, do not reuse the *Exact helpers unless your binary width is exactly 2/4/8; write a sized Codec instead."],"exampleFix":"// before — wrong exact helper for a custom 16-byte type\nplans := pgtype.ScanPlanFuncs{}\nplans.Register(oid, func(m *pgtype.Map, src []byte) (any, error) {\n    return pgio.Uint32Exact(src) // wrong size -> \"invalid length\"\n})\n\n// after — sized codec matching the real binary width\nfunc (c *MyCodec) DecodeBinary(m *pgtype.Map, src []byte) (any, error) {\n    if len(src) != 16 { return nil, fmt.Errorf(\"bad len %d\", len(src)) }\n    /* decode 16 bytes */\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"func isInvalidLength(err error) bool { return errors.Is(err, pgio.ErrInvalidLength) }","tryCatchPattern":"v, err := plan.Scan(typeMap, src)\nif errors.Is(err, pgio.ErrInvalidLength) {\n    // wrong-length binary payload for a fixed-size type\n    log.Printf(\"invalid length for oid=%d: got %d bytes\", oid, len(src))\n    return nil, err\n}","preventionTips":["Verify OID→codec mappings in your TypeMap.","Do not reuse Uint*Exact helpers for non-2/4/8-byte types.","Match pgx version to server version.","For custom scalars, write a Codec that validates len(src)."],"tags":["decode","binary-protocol","type-mapping","pgio"],"analyzedSha":"ec1a0befd22592cffffdeeb0a50311b506372f4c","analyzedAt":"2026-08-04T22:52:11.263Z","schemaVersion":2}