Skip to content

fix: remove rows.Err() from Scan to prevent deadlock (#7403)#7720

Open
DukeDeSouth wants to merge 1 commit intogo-gorm:masterfrom
DukeDeSouth:fix/scanrows-deadlock-7403
Open

fix: remove rows.Err() from Scan to prevent deadlock (#7403)#7720
DukeDeSouth wants to merge 1 commit intogo-gorm:masterfrom
DukeDeSouth:fix/scanrows-deadlock-7403

Conversation

@DukeDeSouth
Copy link
Copy Markdown

Scan() calls rows.Err() after scanning, which can deadlock when a context
cancellation goroutine (awaitDone) tries to WLock the internal closemu
RWMutex concurrently. Since rows.Err() needs an RLock, it blocks behind
the pending WLock — permanent deadlock, leaked DB connection.

This moves the rows.Err() responsibility to the 4 callback callers that
actually own the rows lifecycle. Each now calls !rows.Next() before
rows.Err(), ensuring all locks are released first. ScanRows (public API)
is unchanged — callers manage their own lifecycle per standard Go patterns.

Same logical fix as #7404, rebased cleanly on current HEAD.

  • Do only one thing
  • Non breaking API changes
  • Tested

Made with Cursor

Scan() called rows.Err() after scanning, but rows.Err() acquires
an RLock on the internal closemu RWMutex. When context cancellation
fires concurrently, the awaitDone goroutine tries to acquire WLock
for rows.Close(). If any prior RLock is still held, the WLock blocks,
and the subsequent rows.Err() RLock blocks behind the pending WLock
— classic RWMutex deadlock. The leaked DB connection never closes.

The fix moves error checking to the 4 callback callers that own the
rows lifecycle. Each caller now calls rows.Next() before rows.Err()
to ensure locks are released and rows are fully consumed. rows.Next()
returns false when iteration is done, making rows.Err() safe to call.

ScanRows() (public API) is unchanged — callers already manage their
own rows lifecycle per standard Go database/sql conventions.

Made-with: Cursor
@jinzhu
Copy link
Copy Markdown
Member

jinzhu commented Mar 21, 2026

why it cause deadlock? can you add some tests?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants