jaegertracing/jaeger · error
failed to scan span row: %w
Error message
failed to scan span row: %w
What it means
After the query succeeds, each row is decoded via dbmodel.ScanRow; if row scanning fails (column/type mismatch between the ClickHouse schema and the dbmodel scan targets), the error is appended and row iteration breaks. The wrapped error is the clickhouse driver's scan error identifying which column/type failed.
Source
Thrown at internal/storage/v2/clickhouse/tracestore/reader.go:87
func (r *Reader) GetTraces(
ctx context.Context,
traceIDs ...tracestore.GetTraceParams,
) iter.Seq2[[]ptrace.Traces, error] {
return func(yield func([]ptrace.Traces, error) bool) {
for _, traceID := range traceIDs {
query, args := buildGetTracesQuery(traceID)
rows, err := r.conn.Query(ctx, query, args...)
if err != nil {
yield(nil, fmt.Errorf("failed to query trace: %w", err))
return
}
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
}View on GitHub (pinned to 806f444784)
Solutions
- Apply the matching ClickHouse schema migrations for your jaeger version
- Compare the table's DESCRIBE output with the columns dbmodel.ScanRow expects and reconcile differences
- Find the failing column in the wrapped error and fix its type/nullability
- Re-ingest or transform rows written by incompatible producer versions
Example fix
// before (old schema missing a column ScanRow expects) ALTER TABLE spans ADD COLUMN events String; // after (run provided migrations instead of ad-hoc edits) jaeger-ch-schema migrate --version=<matching-version>
Defensive patterns
Strategy: try-catch
Validate before calling
// verify schema compatibility before deploying cols, err := conn.Query(ctx, "DESCRIBE TABLE spans") // compare column names/types/nullability against dbmodel.ScanRow's expectations
Try / catch
for traces, err := range reader.GetTraces(ctx, ids) {
if err != nil {
if strings.Contains(err.Error(), "failed to scan span row") {
log.Printf("schema mismatch on span row: %v", err) // investigate schema, not network
}
return err
}
process(traces)
} Prevention
- Always run the jaeger ClickHouse schema migrations matching your binary version
- Add a startup schema-version check against the migrations table
- Never hand-edit ClickHouse table schemas for jaeger tables
- Test upgrades against a copy of production data to catch scan mismatches
When it happens
Trigger: Calling GetTraces against a table whose schema differs from what dbmodel.ScanRow expects — e.g. columns added/removed/renamed by a schema version mismatch, NULL values in non-nullable scan targets, or incompatible column types (String vs UInt64).
Common situations: Running new jaeger code against an old un-migrated ClickHouse schema (or vice versa); manual schema edits; data written by a different jaeger version with different column encoding.
Related errors
- failed to scan row: %w
- failed to scan dependency row: %w
- failed to get attribute metadata: %w
- query exists in template without ";"
- TraceID is not a 128bit integer
AI-assisted analysis of jaegertracing/jaeger@806f444784 (2026-09-01).
Data as JSON: /api/errors/6152301cbdb0051b.
Report an issue: GitHub.