jackc/pgx · error
invalid digitsRead: (this can't happen)
Error message
invalid digitsRead: %d (this can't happen)
What it means
While accumulating nbase digit groups into a big.Int, the loop selects a power-of-10000 multiplier based on how many digits the helper read (1-4). This guard fires when digitsRead is outside 1-4 — an internal invariant violation the message itself labels 'this can't happen'. It indicates a bug in the digit-reading helper or memory corruption, not bad user input.
Solutions
- Report as a pgx bug with the numeric value that triggered it
- Upgrade to the latest pgx — the nbase accumulation loop has had correctness fixes
- Try text format for the column to bypass binary decoding
Defensive patterns
Strategy: fallback
When it happens
Trigger: Thrown at pgtype/numeric.go:676 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of jackc/pgx@ec1a0befd2 (2026-08-04).
Data as JSON: /api/errors/e173577cc72b2f91.
Report an issue: GitHub.
Appendix: source
Thrown at pgtype/numeric.go:676
// int(ndigits) before the addition: ndigits is a uint16, so ndigits+3
// would wrap for counts above 65532 and skip the loop entirely.
for i := 0; i < (int(ndigits)+3)/4; i++ {
int64accum, digitsRead := nbaseDigitsToInt64(r, int(ndigits)-i*4)
if i > 0 {
var mul *big.Int
switch digitsRead {
case 1:
mul = bigNBase
case 2:
mul = bigNBaseX2
case 3:
mul = bigNBaseX3
case 4:
mul = bigNBaseX4
default:
return fmt.Errorf("invalid digitsRead: %d (this can't happen)", digitsRead)
}
accum.Mul(accum, mul)
}
accum.Add(accum, big.NewInt(int64accum))
}
if err := r.Finish(); err != nil {
return fmt.Errorf("numeric: %w", err)
}
exp := (int32(weight) - int32(ndigits) + 1) * 4
if dscale > 0 {
fracNBaseDigits := int(ndigits) - int(weight) - 1
fracDecimalDigits := fracNBaseDigits * 4
dscaleInt := int(dscale)
View on GitHub (pinned to ec1a0befd2)