defer for cleanup — always use error-checked closures
Every deferred cleanup call that returns an error MUST check and log the error.
Never use bare defer X.Close() — the discarded error hides resource leak failures.
defer rows.Close()
rows, err := db.QueryContext(ctx, query)
if err != nil { return fmt.Errorf("querying tasks: %w", err) }
defer func() {
if err := rows.Close(); err != nil {
slog.Warn("failed to close rows", "error", err, "operation", "ListTasks")
}
}()
Transaction rollback:
defer tx.Rollback()
defer func() {
if err := tx.Rollback(); err != nil && !errors.Is(err, sql.ErrTxDone) {
slog.Error("failed to rollback transaction", "error", err, "operation", "CreateOrder")
}
}()
HTTP response body:
defer resp.Body.Close()
defer func() {
if _, err := io.Copy(io.Discard, resp.Body); err != nil {
slog.Warn("failed to drain response body", "error", err)
}
if err := resp.Body.Close(); err != nil {
slog.Warn("failed to close response body", "error", err)
}
}()