Panic while row.Scan: rows.resultReader is nil
Nobody has claimed this yet.
- Dominant language
- Go
- Stars
- 14.3k
- Forks
- 1.1k
- Avg merge
- 6d 9h
- Merged PRs (30d)
- 11
Description
Hi, Jackc!
**Describe the bug**
Just making a sql query. It panics on row.Scan
row := n.dbPing.db.QueryRowContext(ctx, query)
err = row.Scan(&closed, &isMaster, &lag) <------ panic here
**To Reproduce**
I don't know
**Expected behavior**
no panic
**Actual behavior**
panic
**Version**
- Go: `$ go version` -> [go version go1.21.3 linux/amd64]
- PostgreSQL: `$ psql --no-psqlrc --tuples-only -c 'select version()'` -> [PostgreSQL 12.16 (Ubuntu 12.16-201-yandex.49498.ecc66a0ba4) on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0, 64-bit]
- pgx: `$ grep 'github.com/jackc/pgx/v[0-9]' go.mod` -> [4.17.2]
**Additional context**
Sorry I have no idea how to reproduce it.
But seems like in any case it should not panic.
Can you please help us here and clear up what's going on?
I think a fix is needed, but I have no idea how.
Here I have some core dump
StackTrace:
```
(dlv) bt
0 0x00000000031b1c41 in runtime.raise
at /-S/contrib/go/_std_1.21/src/runtime/sys_linux_amd64.s:154
1 0x00000000031913a5 in runtime.dieFromSignal
at /-S/contrib/go/_std_1.21/src/runtime/signal_unix.go:903
2 0x0000000003191aa6 in runtime.sigfwdgo
at /-S/contrib/go/_std_1.21/src/runtime/signal_unix.go:1108
3 0x00000000031900a5 in runtime.sigtrampgo
at /-S/contrib/go/_std_1.21/src/runtime/signal_unix.go:432
4 0x00000000031b1c41 in runtime.raise
at /-S/contrib/go/_std_1.21/src/runtime/sys_linux_amd64.s:153
5 0x00000000031913a5 in runtime.dieFromSignal
at /-S/contrib/go/_std_1.21/src/runtime/signal_unix.go:903
6 0x000000000317a545 in runtime.crash
at /-S/contrib/go/_std_1.21/src/runtime/signal_unix.go:985
7 0x000000000317a545 in runtime.fatalpanic
at /-S/contrib/go/_std_1.21/src/runtime/panic.go:1215
8 0x0000000003179c8c in runtime.gopanic
at /-S/contrib/go/_std_1.21/src/runtime/panic.go:1017
9 0x00000000031912d8 in runtime.panicmem
at /-S/contrib/go/_std_1.21/src/runtime/panic.go:261
10 0x00000000031912d8 in runtime.sigpanic
at /-S/contrib/go/_std_1.21/src/runtime/signal_unix.go:861
11 0x000000000369a3e7 in github.com/jackc/pgx/v4.(*connRows).FieldDescriptions
at /-S/vendor/github.com/jackc/pgx/v4/rows.go:120
12 0x0000000003bc116f in github.com/jackc/pgx/v4/stdlib.(*Rows).Columns
at /-S/vendor/github.com/jackc/pgx/v4/stdlib/sql.go:510
13 0x00000000033c3ce4 in database/sql.(*Rows).nextLocked
at /-S/contrib/go/_std_1.21/src/database/sql/sql.go:3016
14 0x00000000033c3c09 in database/sql.(*Rows).Next.func1
at /-S/contrib/go/_std_1.21/src/database/sql/sql.go:2994
15 0x00000000033c60c2 in database/sql.withLock
at /-S/contrib/go/_std_1.21/src/database/sql/sql.go:3502
16 0x00000000033c3b85 in database/sql.(*Rows).Next
at /-S/contrib/go/_std_1.21/src/database/sql/sql.go:2993
17 0x00000000033c5b2a in database/sql.(*Row).Scan
at /-S/contrib/go/_std_1.21/src/database/sql/sql.go:3439
18 0x0000000003bd033d in a.yandex-team.ru/mds/s3/goose/internal/db/postgres/clusters.(*shardNode).hostState.func2
at /-S/mds/s3/goose/internal/db/postgres/clusters/host.go:87
19 0x00000000031b03c1 in runtime.goexit
at /-S/contrib/go/_std_1.21/src/runtime/asm_amd64.s:1650
```
r.rows in `/-S/vendor/github.com/jackc/pgx/v4/stdlib/sql.go:510`
```
(dlv) print r
("*github.com/jackc/pgx/v4/stdlib.Rows")(0xc04671ac30)
*github.com/jackc/pgx/v4/stdlib.Rows {
conn: *github.com/jackc/pgx/v4/stdlib.Conn {
conn: *(*"github.com/jackc/pgx/v4.Conn")(0xc00791dc20),
psCount: 0,
driver: *(*"github.com/jackc/pgx/v4/stdlib.Driver")(0xc0009326f0),
connConfig: (*"github.com/jackc/pgx/v4.ConnConfig")(0xc018ab23d8),
resetSessionFunc: github.com/jackc/pgx/v4/stdlib.(*driverConnector).Connect.func1,},
rows: github.com/jackc/pgx/v4.Rows(*github.com/jackc/pgx/v4.connRows) *{
ctx: context.Context(*context.cancelCtx) ...,
logger: github.com/jackc/pgx/v4.rowLog(*github.com/jackc/pgx/v4.Conn) ...,
connInfo: *(*"github.com/jackc/pgtype.ConnInfo")(0xc045385a10),
values: [][]uint8 len: 0, cap: 0, nil,
rowCount: 0,
err: error nil,
commandTag: github.com/jackc/pgconn.CommandTag len: 0, cap: 0, nil,
startTime: (*time.Time)(0xc02997ad90),
sql: "/* sql: shard_node_host_state */\nSELECT current_setting('pgcheck...+300 more",
args: []interface {} len: 0, cap: 0, [],
closed: true,
conn: *(*"github.com/jackc/pgx/v4.Conn")(0xc00791dc20),
resultReader: *github.com/jackc/pgconn.ResultReader nil,
multiResultReader: *github.com/jackc/pgconn.MultiResultReader nil,
scanPlans: []github.com/jackc/pgtype.ScanPlan len: 0, cap: 0, nil,},
valueFuncs: []github.com/jackc/pgx/v4/stdlib.rowValueFunc len: 0, cap: 0, nil,
skipNext: true,
skipNextMore: false,
columnNames: []string len: 0, cap: 0, nil,}
(dlv) print r.rows
github.com/jackc/pgx/v4.Rows(*github.com/jackc/pgx/v4.connRows) *{
ctx: context.Context(*context.cancelCtx) *{
Context: context.Context(*context.valueCtx) ...,
mu: (*sync.Mutex)(0xc043ddc8d0),
done: (*"sync/atomic.Value")(0xc043ddc8d8),
children: map[context.canceler]struct {} [],
err: error nil,
cause: error nil,},
logger: github.com/jackc/pgx/v4.rowLog(*github.com/jackc/pgx/v4.Conn) *{
pgConn: *(*"github.com/jackc/pgconn.PgConn")(0xc0794c62c0),
config: *(*"github.com/jackc/pgx/v4.ConnConfig")(0xc0018b3320),
preparedStatements: map[string]*github.com/jackc/pgconn.StatementDescription [],
stmtcache: github.com/jackc/pgconn/stmtcache.Cache(*github.com/jackc/pgconn/stmtcache.LRU) ...,
logger: github.com/jackc/pgx/v4.Logger(*a.yandex-team.ru/mds/s3/goose/internal/db/postgres/pgcommon.PgxLogger) ...,
logLevel: 4,
notifications: []*github.com/jackc/pgconn.Notification len: 0, cap: 0, nil,
doneChan: chan struct {} {
qcount: 0,
dataqsiz: 0,
buf: *[0]struct struct {} [],
elemsize: 0,
closed: 0,
elemtype: *internal/abi.Type {Size_: 0, PtrBytes: 0, Hash: 3842252374, TFlag: TFlagExtraStar|TFlagRegularMemory (10), Align_: 1, FieldAlign_: 1, Kind_: 25, Equal: runtime.memequal0, GCData: *0, Str: 77680, PtrToThis: 0},
sendx: 0,
recvx: 0,
recvq: waitq {
first: *sudog nil,
last: *sudog nil,},
sendq: waitq {
first: *sudog nil,
last: *sudog nil,},
lock: runtime.mutex {
lockRankStruct: runtime.lockRankStruct {},
key: 0,},},
closedChan: chan error {
qcount: 0,
dataqsiz: 0,
buf: *[0]error [],
elemsize: 16,
closed: 0,
elemtype: *internal/abi.Type {Size_: 16, PtrBytes: 16, Hash: 805568309, TFlag: TFlagUncommon|TFlagExtraStar|TFlagNamed (7), Align_: 8, FieldAlign_: 8, Kind_: 20, Equal: runtime.interequal, GCData: *2, Str: 14032, PtrToThis: 944800},
sendx: 0,
recvx: 0,
recvq: waitq {
first: *sudog nil,
last: *sudog nil,},
sendq: waitq {
first: *sudog nil,
last: *sudog nil,},
lock: runtime.mutex {
lockRankStruct: runtime.lockRankStruct {},
key: 0,},},
connInfo: *(*"github.com/jackc/pgtype.ConnInfo")(0xc045385a10),
wbuf: []uint8 len: 0, cap: 1024, [],
eqb: (*"github.com/jackc/pgx/v4.extendedQueryBuilder")(0xc00791dca8),},
connInfo: *github.com/jackc/pgtype.ConnInfo {
oidToDataType: map[uint32]*github.com/jackc/pgtype.DataType [...],
nameToDataType: map[string]*github.com/jackc/pgtype.DataType [...],
reflectTypeToName: map[reflect.Type]string [...],
oidToParamFormatCode: map[uint32]int16 [...],
oidToResultFormatCode: map[uint32]int16 [...],
reflectTypeToDataType: map[reflect.Type]*github.com/jackc/pgtype.DataType nil,},
values: [][]uint8 len: 0, cap: 0, nil,
rowCount: 0,
err: error nil,
commandTag: github.com/jackc/pgconn.CommandTag len: 0, cap: 0, nil,
startTime: time.Time(2023-12-06T23:00:36+03:00, +18710383674571){
wall: 13930850365381015637,
ext: 18710383674571,
loc: *(*time.Location)(0x5cec620),},
sql: "/* sql: shard_node_host_state */\nSELECT current_setting('pgcheck...+300 more",
args: []interface {} len: 0, cap: 0, [],
closed: true,
conn: *github.com/jackc/pgx/v4.Conn {
pgConn: *(*"github.com/jackc/pgconn.PgConn")(0xc0794c62c0),
config: *(*"github.com/jackc/pgx/v4.ConnConfig")(0xc0018b3320),
preparedStatements: map[string]*github.com/jackc/pgconn.StatementDescription [],
stmtcache: github.com/jackc/pgconn/stmtcache.Cache(*github.com/jackc/pgconn/stmtcache.LRU) ...,
logger: github.com/jackc/pgx/v4.Logger(*a.yandex-team.ru/mds/s3/goose/internal/db/postgres/pgcommon.PgxLogger) ...,
logLevel: 4,
notifications: []*github.com/jackc/pgconn.Notification len: 0, cap: 0, nil,
doneChan: chan struct {} {
qcount: 0,
dataqsiz: 0,
buf: *[0]struct struct {} [],
elemsize: 0,
closed: 0,
elemtype: *internal/abi.Type {Size_: 0, PtrBytes: 0, Hash: 3842252374, TFlag: TFlagExtraStar|TFlagRegularMemory (10), Align_: 1, FieldAlign_: 1, Kind_: 25, Equal: runtime.memequal0, GCData: *0, Str: 77680, PtrToThis: 0},
sendx: 0,
recvx: 0,
recvq: waitq {
first: *sudog nil,
last: *sudog nil,},
sendq: waitq {
first: *sudog nil,
last: *sudog nil,},
lock: runtime.mutex {
lockRankStruct: runtime.lockRankStruct {},
key: 0,},},
closedChan: chan error {
qcount: 0,
dataqsiz: 0,
buf: *[0]error [],
elemsize: 16,
closed: 0,
elemtype: *internal/abi.Type {Size_: 16, PtrBytes: 16, Hash: 805568309, TFlag: TFlagUncommon|TFlagExtraStar|TFlagNamed (7), Align_: 8, FieldAlign_: 8, Kind_: 20, Equal: runtime.interequal, GCData: *2, Str: 14032, PtrToThis: 944800},
sendx: 0,
recvx: 0,
recvq: waitq {
first: *sudog nil,
last: *sudog nil,},
sendq: waitq {
first: *sudog nil,
last: *sudog nil,},
lock: runtime.mutex {
lockRankStruct: runtime.lockRankStruct {},
key: 0,},},
connInfo: *(*"github.com/jackc/pgtype.ConnInfo")(0xc045385a10),
wbuf: []uint8 len: 0, cap: 1024, [],
eqb: (*"github.com/jackc/pgx/v4.extendedQueryBuilder")(0xc00791dca8),},
resultReader: *github.com/jackc/pgconn.ResultReader nil,
multiResultReader: *github.com/jackc/pgconn.MultiResultReader nil,
scanPlans: []github.com/jackc/pgtype.ScanPlan len: 0, cap: 0, nil,}
(dlv) print r.rows.resultReader
*github.com/jackc/pgconn.ResultReader nil
```
Some milliseconds before the panic (and seconds before, several times) we got error from this db host
`dial error (timeout: dial tcp [2a02:6b8:c00:1003:0:1589:f18d:ef59]:6432: connect: connection timed out)`
But this error did not produce panic
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reading pgx/v4/rows.go:120 and pgx/v4/stdlib/sql.go:510, then trace how the connection timeout and closed rows state reach Row.Scan. Use the provided stack trace and state dump to investigate the nil resultReader path. Done means the same failure returns an error instead of panicking.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go, postgresql
- Domain
- backend, database
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 35/100