Skip to content

False positive on sqlx.Rows closed inside defer closure #49

Description

@Orfeo42

sqlclosecheck reports a false positive when *sqlx.Rows returned by NamedQueryContext is closed inside a defer func() { ... }() block.

golangci-lint version: v2.11.4 (Docker image golangci/golangci-lint:latest-alpine)

Reproducer:

rows, err := r.db.NamedQueryContext(ctx, query, map[string]any{"id": id})
if err != nil {
    return nil, err
}

defer func() {
    if closeErr := rows.Close(); closeErr != nil {
        slog.WarnContext(ctx, "failed to close rows",
            "error", closeErr,
        )
    }
}()

// ... rows.Next(), StructScan, etc.

Linter output:

repository.go:51:37: Rows/Stmt/NamedStmt was not closed (sqlclosecheck)
        rows, err := r.db.NamedQueryContext(ctx, query, map[string]any{"id": id})
                                           ^

Expected behavior: No error — rows.Close() is called inside the deferred closure, which guarantees cleanup on all return paths.

Observed behavior: sqlclosecheck does not recognize rows.Close() when it appears inside defer func() { ... }() and reports the rows as unclosed.

Notes:

  • r.db is *sqlx.DB, so NamedQueryContext returns *sqlx.Rows.
  • The same code passes with golangci-lint v2.11.3 (sqlclosecheck does not flag it). The regression appeared in v2.11.4.
  • Using defer rows.Close() (without the closure) is recognized correctly, but discards the error from Close().

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions