jaegertracing/jaeger · warning

failed to close rows: %w

Error message

failed to close rows: %w

What it means

When rows.Close() returns an error after finishing iteration in Reader.GetTraces, it is appended to the error list and yielded as part of the joined error. clickhouse-go's Close can fail when releasing the connection if the connection is already broken, so this typically accompanies (or masks) an earlier streaming failure.

Source

Thrown at internal/storage/v2/clickhouse/tracestore/reader.go:100

			var errs []error
			for rows.Next() {
				span, scanErr := dbmodel.ScanRow(rows)
				if scanErr != nil {
					errs = append(errs, fmt.Errorf("failed to scan span row: %w", scanErr))
					break
				}
				trace := dbmodel.FromRow(span)
				if !yield([]ptrace.Traces{trace}, nil) {
					_ = rows.Close()
					return
				}
			}
			if rowsErr := rows.Err(); rowsErr != nil {
				errs = append(errs, fmt.Errorf("failed to read span rows: %w", rowsErr))
			}
			if closeErr := rows.Close(); closeErr != nil {
				errs = append(errs, fmt.Errorf("failed to close rows: %w", closeErr))
			}
			if err := errors.Join(errs...); err != nil {
				yield(nil, err)
				return
			}
		}
	}
}

func (r *Reader) GetServices(ctx context.Context) ([]string, error) {
	rows, err := r.conn.Query(ctx, sql.SelectServices)
	if err != nil {
		return nil, fmt.Errorf("failed to query services: %w", err)
	}

	var (
		services []string
		errs     []error

View on GitHub (pinned to 806f444784)

Solutions

  1. Inspect the joined error (errors.Join output) — the primary cause is usually the earlier wrapped error, not the close itself
  2. Fix the underlying connection/timeout problem; the close error is secondary
  3. Ensure queries honor context cancellation so teardown is clean
  4. Keep clickhouse-go driver versions current, as older versions had close-error edge cases

Example fix

// before
cancelledCtx, cancel := context.WithCancel(ctx)
cancel()
rows, _ := conn.Query(cancelledCtx, q) // close fails on cancelled conn
// after
rows, _ := conn.Query(ctx, q) // let iteration finish before teardown
Defensive patterns

Strategy: try-catch

Validate before calling

// ensure clean cancellation semantics before querying
ctx, cancel := context.WithTimeout(ctx, queryTimeout)
defer cancel()

Try / catch

err := doQuery(ctx)
if err != nil {
	// close errors are joined; inspect each with errors.Unwrap
	for e := err; e != nil; e = errors.Unwrap(e) {
		if strings.Contains(e.Error(), "failed to close rows") {
			log.Printf("secondary close failure: %v", e)
			break
		}
	}
}

Prevention

When it happens

Trigger: GetTraces iteration completes (or breaks on a scan error) and the subsequent rows.Close() call fails because the connection was reset, the query was cancelled, or the underlying TCP conn is in a bad state.

Common situations: Network instability between jaeger and ClickHouse; context cancellation racing with query teardown; server-side kills (max_execution_time, memory limits) leaving the connection unusable for release.

Related errors


AI-assisted analysis of jaegertracing/jaeger@806f444784 (2026-09-01). Data as JSON: /api/errors/ec24e30028acc938. Report an issue: GitHub.