Fabrizio Spini
06/24/2026, 12:38 PMsourceCatalogId even on empty schema diff
Setup
⢠Airbyte 2.1.0, self-hosted on GKE
⢠source-mysql:3.51.5 (CDC mode, invalid_cdc_cursor_position_behavior: Fail sync)
⢠destination-bigquery:3.0.16
⢠nonBreakingChangesPreference: ignore
What happens
Every night at midnight UTC a scheduled discover runs. When it completes, ConnectionsHandler.applySchemaChange() updates the connection's sourceCatalogId ā even when the schema diff is empty. New syncs launched under the new catalogId find no associated CDC state and fall back to an old saved binlog position.
The result is a silent, growing backlog: each sync reprocesses an ever-increasing number of records from the old binlog position. In our case this grew from ~2M to ~55M records over 2 days before BigQuery started returning 500s and the sync loop became permanent.
Why nonBreakingChangesPreference: ignore doesn't help
This setting controls stream-level propagation, but applySchemaChange() still updates sourceCatalogId on every discover completion regardless. The CDC state orphaning happens upstream of that logic.
Impact
⢠Pipeline silently accumulates backlog for days without alerting
⢠Failure only surfaces when destination (BigQuery) starts rejecting large batch inserts
⢠By then the binlog position in the CDC state may no longer exist (rotated out)
Question
Is this a known issue? Is there a way to prevent sourceCatalogId from being updated when there's no actual schema change? We couldn't find a config option that controls this behavior.
Current mitigation
We deployed a Cloud Run job (hourly) that queries sync stats and alerts on Slack if any CDC connection shows 5 consecutive runs with monotonically increasing records emitted where the latest run processes >2x the records of the oldest in the window. This lets us catch the backlog early before volumes become critical.
Thanks šMatt Bayley
06/24/2026, 6:54 PMNew syncs launched under the newThe catalog ID points to the catalog (schema), not the state, which holds the binlog position. I'd have to dig into this a bit to determine if the intended behavior is to get a newfind no associated CDC state and fall back to an old saved binlog position.catalogId
catalogId when the schema hasn't changed, but my understanding is that this would cause some duplication in the config database at worst.Fabrizio Spini
06/25/2026, 8:54 AM{file=dbabc84.070806, pos=52663308}
⢠Reads all the way to dbabc84.070841/33986269 (32K records)
⢠checkpoint of 1 state message(s) emitted ā sync completes successfully
Sync 606240 (11:06 CEST, one hour later):
⢠Found previous partition offset: {file=dbabc84.070806, pos=52663308} ā exact same offset
This repeats for every subsequent hourly sync. The checkpoint is emitted by the source but the state in the Airbyte platform DB is never updated beyond 070806/52663308.
One other thing we noticed: generateColdStartOffset is called at the beginning of every sync (not just when there's no prior state). Not sure if that's expected or relevant here.
Happy to share the full logs if it helps.Matt Bayley
06/25/2026, 4:58 PMFabrizio Spini
06/26/2026, 9:43 AMfinance_automation CDC connection (MySQL ā BigQuery, Airbyte 2.1.0, source-mysql:3.51.5).
The behaviour in a nutshell: the CDC state (binlog offset) is emitted as a checkpoint by the source but never persisted ā so every sync restarts from the same stale position.
What the logs show:
⢠Sync 605745 (09:06 CEST, June 18) ā healthy sync. Reads from dbabc84.070735/15615386, advances to 070806, emits checkpoint of 1 state message(s).
⢠Sync 605992 (10:06 CEST, +1h) ā first stuck sync. getPreviousOffsets returns {file=dbabc84.070806, pos=52663308} ā correct, it picked up the offset from 605745. Reads binlog from 070806 to 070841, emits checkpoint of 1 state message(s). All looks fine.
⢠Sync 606240 (11:06 CEST, +1h) ā confirms the bug. getPreviousOffsets again returns {file=dbabc84.070806, pos=52663308} ā the exact same offset as the previous sync, despite 605992 having emitted its checkpoint. The state was never saved.
From this point on, every hourly sync reprocesses a growing window of binlog (from 070806 to whatever the current position is), causing exponentially increasing records_emitted.
Additional observation: generateColdStartOffset is called at the very start of every sync (not just cold starts), constructing a synthetic offset pointing to the current binlog tip. We're not sure if this is intentional and whether it could interfere with how the real offset is loaded or committed.
Let me know if you need more syncs or the full raw logs.Matt Bayley
06/26/2026, 8:05 PMstate table in the Postgres instance and check whether the binlog position is advancing there. Also, you could view the state in the UI under Settings -> Connection State, save that somewhere, run a sync, and compare the new state to the old one.