Summary
SchemaRegistry.Refresh iterates system.columns rows but never checks rows.Err(), so a transient error partway through the result set swaps in a partial schema as authoritative and logs it as a success.
Detail
internal/discovery/discovery.go:84-108: the for rows.Next() loop ends on error as well as EOF; driver.Rows.Err() (present in clickhouse-go v2.46) is never consulted. A network hiccup / cancellation mid-result yields a truncated tables map that is installed under lock and logged "schema registry refreshed".
Because auto-refresh runs every 60s, a single transient stream error makes tables after the break disappear (ingest/query → 404), truncates the last table's column list (valid rows rejected as "unknown/missing column"; select_all silently drops columns) — until the next successful refresh. Fail-silent where the rest of boot is fail-loud.
Fix direction
Check rows.Err() after the loop and return the error without swapping sr.tables.
Found in a repo-wide audit; verified by code trace.
Summary
SchemaRegistry.Refreshiteratessystem.columnsrows but never checksrows.Err(), so a transient error partway through the result set swaps in a partial schema as authoritative and logs it as a success.Detail
internal/discovery/discovery.go:84-108: thefor rows.Next()loop ends on error as well as EOF;driver.Rows.Err()(present in clickhouse-go v2.46) is never consulted. A network hiccup / cancellation mid-result yields a truncatedtablesmap that is installed under lock and logged "schema registry refreshed".Because auto-refresh runs every 60s, a single transient stream error makes tables after the break disappear (ingest/query → 404), truncates the last table's column list (valid rows rejected as "unknown/missing column";
select_allsilently drops columns) — until the next successful refresh. Fail-silent where the rest of boot is fail-loud.Fix direction
Check
rows.Err()after the loop and return the error without swappingsr.tables.Found in a repo-wide audit; verified by code trace.