Validator
Overview
|
How-to guide
For step-by-step walkthroughs tested on a running Gluesync, see Validate data with the Validator (filters, date and time conversions, edge cases) and Find and fix row differences between source and target. |
Validator compares one replicated entity with the table or collection it is written to. It reports rows that exist only on the source, rows that exist only on the target, rows whose values differ, and schema differences. From the same screen you can write the source values back to the target (reconcile) or leave the differences in place and alert on them.
Open it from the Control Plane navigation, from an entity’s overflow menu (Validate), or from the entity detail Inspect tables actions. Those links open /data-comparison with pipelineId and entityId already selected.
Validator compares one entity at a time. A pipeline-wide check is a sequence of entity runs, which is how Chronos schedules it.
What a run compares
Each run walks the source and the target in the same key order and records:
| Difference | Meaning |
|---|---|
|
The key exists on the source and not on the target. Reconciliation inserts the source row. |
|
The key exists on the target and not on the source. Reconciliation deletes the target row. |
|
The key exists on both sides and at least one compared column differs. Reconciliation updates the target from the source. |
|
A column cannot be compared (missing, or a type that cannot be aligned). Schema differences are counted and are not rewritten as row fixes. |
A finished run is one of:
| Status | Meaning |
|---|---|
|
Accepted, not started. |
|
Scanning. |
|
Finished with no differences. |
|
Finished, and at least one difference was stored. A run also ends with this status when it stopped at the difference limit, or when a count-only run found different row counts. See Statuses in the Control Plane. |
|
The run stopped on an error. |
|
Stopped before completion. Cancelling does not emit a terminal validation event. |
Run it from the Control Plane
-
Open Validator and pick the pipeline and entity. The source agent, target agent, and primary key are taken from the entity.
-
Optionally narrow the compared columns, add a
WHEREfilter per side, or set ordering expressions when the key type needs an explicit cast. -
Start the run. The summary shows rows scanned and the four difference counters.
-
Open a difference to see the key and the column values. Mismatched cells are marked on the row.
-
Select differences and reconcile them, or reconcile the whole run. Counters update as fixes are applied.
Reconcile writes to the target. It does not change the source.
What the results mean
A run shows a status, a set of counters, a grid of differences, and sometimes a list of notices. Every run of the entity is also listed in Run history at the bottom of the page. Select a run to read it.
The run summary
| Field in the Control Plane | Meaning | Name in the API |
|---|---|---|
Status badge |
Where the run is. See Statuses in the Control Plane. |
|
Run |
The first part of the run’s job id. Hover over it to see the whole id. |
|
Started, Took |
When the run started and how long it ran. While the run is active, Took reads In progress. |
|
Source rows scanned, Target rows scanned |
Rows read so far on each side, then the total each side held when the run started, for example |
|
Source only |
Keys that exist in the source and not in the target. The target is missing the row. |
|
Target only |
Keys that exist in the target and not in the source. The target holds a row that the source no longer has, or never had. |
|
Rows that differ |
Keys that exist on both sides with at least one different value in a compared column. |
|
Schema differences |
Columns that cannot be compared: missing on one side, or with types that cannot be aligned. Notices are not counted here. |
|
Extra in target |
Rows that the target holds and that the pipeline would never have written, because the entity’s filter or its UDF leaves them out. |
|
Not written by the pipeline |
Source rows that the pipeline does not write, because the entity’s filter or its UDF drops them. They are expected to be absent from the target, so they are not differences. |
|
Duplicate keys |
Comparison keys that more than one row holds on one side. |
|
NULL keys |
Rows with a |
|
Transient, discarded |
Differences that were gone when Validator read them again, for example rows the pipeline was still writing. They are not reported. |
|
The summary shows a dash when a counter has no value. The Run history table lists the same counters as columns: Status, Run, Started, Duration, Source rows, Target rows, Source only, Target only, Diff, Extra, and Schema. Hover over a status in that table to read the error of a failed run.
A run does not refresh after you reconcile. The grid shows the old rows until you start a new run.
Count-only runs
A run with Count only on reads no row. The summary shows Source rows, Target rows, a row-count line, and Schema differences. The row-count line reads More rows in source, More rows in target, or Row count difference when the counts are equal. The counters for missing and mismatching rows are not computed, and Run history shows a dash for them.
When the two counts differ, the run ends as Completed with warnings. The message under the status badge gives both counts and their difference. Run a full comparison, without Count only, to list the rows.
When the entity’s pipeline has a filter or a UDF that drops rows, the message says so instead. The two counts differ even when the data matches, and only a full comparison tells you which rows are missing.
Statuses in the Control Plane
| Badge | What you see |
|---|---|
Pending, Running |
A progress bar with the rows read so far (Counting rows before the scan before the first read), and Cancel run. Differences are available when the run ends. |
Completed |
No differences found: source and target are in sync for the compared columns and rows. |
Completed with warnings |
One of four cases: the run found differences, found schema differences, stopped at the difference limit, or was a count-only run with different counts. Open the grid. A message under the badge explains the last two cases. |
Failed |
A red message with an error code and the error text. See Error codes on a failed run. |
Cancelled |
This run was cancelled. No differences were recorded. Start a new run. |
Error codes on a failed run
The red message of a failed run shows the errorCode as its title and the errorMessage as its text. The same two fields are on the run summary in the API.
errorCode |
When it appears |
|---|---|
|
The run hit an error that is not one of the cases below. The text is the message of the database or of the agent, for example |
|
The run exceeded Max runtime (seconds): |
|
The run stopped at its runtime limit: |
|
One side returned its keys in an order the run does not expect: |
|
A column of the mapping is not in a table, for example |
|
A run is already active for the entity, or five comparison jobs already run on Core Hub. |
|
The run asked for Validate key uniqueness or refuses |
|
The source or target agent cannot compare data. |
|
Validator could not open its own connection to the database of an agent. |
|
Your role or the data access policy does not allow the comparison. |
Differences in the grid
The grid shows the Source table on the left and the Target table on the right. For a key that exists on both sides, the cells that differ are marked. Hover over the tag of a row to read its description.
| Tag in the grid | Name in the API | Meaning | What Reconcile does |
|---|---|---|---|
Source only |
|
The row is in the source and missing in the target. |
Inserts the source row. |
Target only |
|
The row is in the target and missing in the source. |
Deletes the target row. |
Differs |
|
The row is on both sides with different values. |
Updates the target row with the source values. |
Extra in target |
|
The target holds a row that the pipeline would never have written. |
Deletes it only when Delete target rows the entity filter excludes is ticked in the options. Otherwise it skips the row. |
Duplicate key |
|
More than one row has this comparison key. Pick a unique key to compare these rows. |
Nothing. The row is reported, not fixed. |
NULL key |
|
A comparison key column is |
Nothing. The row is reported, not fixed. |
The three Operations allowed when reconciling options limit what Reconcile may write. A row that an option forbids is skipped, and it stays in the run.
Schema differences
When a column cannot be compared, a card named Schema differences detected lists it with these columns: Column, Issue, Source definition, Target definition, and Discrepancy. The issue is one of:
| Issue | Meaning |
|---|---|
Missing in target |
The column is in the source and not in the target table. |
Missing in source |
The column is in the target and not in the source table. |
Type mismatch |
The two types differ. |
Types not comparable |
The run cannot align the two types, so it leaves the column out. |
Reconcile does not rewrite schema differences.
Notices
A notice says how a column was compared, or why it was not. It is not a difference and it is not counted. The Notices card lists the column, the notice, and a detail. Notices you may see:
| Notice | Meaning |
|---|---|
Equal within tolerance |
A lenient run counted values as equal that match only under a tolerance of the lenient profile. The detail gives the number of values. |
Compared at lower precision |
The two types cannot be compared as strictly as one of them stores the value. The detail names the types. |
Column skipped by an option |
An option of the run leaves the column out, for example Skip BLOB / CLOB columns. |
Target-only column not compared |
A column that exists only in the target is not compared. |
Reader warning |
A warning from the database reader. For example, a text key is ordered with a forced binary collation, so that both sides sort the keys the same way. The warning also names an index that speeds the run up. |
Row count not predictable |
The pipeline drops rows with a filter or a UDF, so the two counts differ even when the data matches. |
Difference limit reached |
The run stopped at Max differences. The rows after that point were not compared. |
Large object truncated, Large object not read |
A large object was cut or could not be read, so its comparison is partial. |
REST API
All routes are on Core Hub. The caller’s role still applies (view, view differences, reconcile, cancel).
Start a run
POST /data-comparison/runs
The smallest body is the pipeline and the entity:
{
"pipelineId": "pipeline-id",
"entityId": "entity-id"
}
When sourceAgentId, targetAgentId, or comparisonKey is omitted or blank, Core Hub fills them from the entity: the source and target agents registered on that entity, and the primary-key columns of the source entity. The Control Plane sends those fields explicitly. Automation (Chronos, MCP) can omit them.
Optional fields:
-
columns— non-key columns to compare. Default is the mapped columns. -
columnMapping— source column name to target column name, when the names differ. -
options—fetchSize(default 10000, max 50000),maxRuntimeSeconds(default 3600, max 86400),maxEmittedDifferences(default 10000, max 50000),countOnly, string and timestamp comparison modes, and reconciliation toggles (reconcileInserts,reconcileDeletes,reconcileUpdates). -
queryOptions—whereConditionSource,whereConditionTarget,orderBySource,orderByTarget. Ordering values are comma-separated SQL expressions, one per key column, with noASC,DESC, orNULLS.
The response is { "jobId", "status": "PENDING", "startedAt" }.
Read a run
-
GET /data-comparison/runs— list runs. OptionalentityIdquery parameter. -
GET /data-comparison/runs/{jobId}— one summary: status, row counts,missingInSourceCount,missingInTargetCount,rowMismatchesCount,schemaDifferencesCount,duplicateKeysCount, timestamps,errorCode,errorMessage. -
GET /data-comparison/runs/{jobId}/differences?limit=&offset=— one page of differences. Each record hasid,differenceType,keyJson, andcolumnDiffsJson. -
DELETE /data-comparison/runs/{jobId}— cancel aPENDINGorRUNNINGrun, or delete a finished run.
Reconcile
POST /data-comparison/runs/{jobId}/reconciliation
{ "reconcileAll": true }
reconcileAll fixes every remaining difference of that run. Core Hub pages the stored differences itself. Use this from Chronos or any client that should not walk difference ids.
To fix a selection instead:
{
"differenceIds": ["diff-id"],
"columns": ["status"]
}
comparisonKey may be omitted. The key saved with the run is used when it is present. columns limits which mismatched columns are written; omitted means every compared column.
The response is insertedCount, deletedCount, updatedCount, and skippedCount. A difference is removed only after its write succeeds. A skipped row stays in the run.
Platform events
Every run emits CloudEvents that webhook subscriptions, email notifications, and in-app notifications can select. The source of the event is the entity.
| Event | Type | Severity | When |
|---|---|---|---|
|
|
INFO |
The run was accepted. |
|
|
INFO |
Status |
|
|
WARNING |
Status |
|
|
CRITICAL |
Status |
|
|
INFO, or WARNING when |
A reconcile call inserted, deleted, updated, or skipped rows. |
Terminal event data contains jobId, status, sourceRowsCount, targetRowsCount, sourceRowsScanned, targetRowsScanned, missingInSourceCount, missingInTargetCount, rowMismatchesCount, schemaDifferencesCount, duplicateKeysCount, totalDifferences, startedAt, and, when present, endedAt, errorCode, and errorMessage.
The reconciled event data contains jobId, insertedCount, deletedCount, updatedCount, skippedCount, and reconcileAll.
Subscribe to these types from Settings → Notifications or a webhook configuration. The event catalog is served by Core Hub (get_webhook_event_types on the MCP server lists the same names).
A Chronos job that validates with reconciliation turned off fails the job and stores the difference breakdown as the job error. That failure is what Chronos sends on its own webhook and email path. The platform events above are emitted by Core Hub whether or not Chronos is the caller. See Schedule validation.
MCP tools
The embedded MCP server exposes six Validator tools. They call the REST routes above with the caller’s token.
| Tool | Category | What it does |
|---|---|---|
|
WRITE |
Starts a run. |
|
READ |
Lists runs, optionally filtered by |
|
READ |
Returns one run summary by |
|
READ |
Returns one page of differences ( |
|
WRITE |
Reconciles |
|
WRITE |
Cancels a running job or deletes a finished run. |
These six tools are part of the 142-tool built-in catalog. See Core Hub MCP server.
Supported connectors
Validator compares a pair of connectors only when both the source agent and the target agent of the entity can compare data. If one of them cannot, the run does not start. See [connector-not-supported].
These connectors compare data as a source and as a target:
-
IBM i
-
Db2 LUW (CDC and triggers)
-
Informix
-
MariaDB
-
MySQL
-
Microsoft SQL Server (CDC and Change Tracking)
-
Oracle (CDC, XStream, triggers, and legacy triggers)
-
PostgreSQL
-
SAP HANA
-
SQL Anywhere
-
Sybase (triggers)
-
Vertica
-
YugabyteDB
-
Couchbase
-
MongoDB
This connector compares data as a source only:
-
Sybase (log reader)
These connectors compare data as a target only:
-
ClickHouse
-
CockroachDB
-
Databricks
-
Google BigQuery
-
GridGain
-
Amazon Redshift
-
SingleStore
-
Snowflake
A connector that is not in these lists cannot take part in a run. For those pairs, use Count both on the entity detail page and Query Studio to check counts and data.
Tables without a primary or logical key
Validator walks both tables in the order of a comparison key and matches rows by that key. It has no way to match rows without one.
-
The comparison key is the set of key columns of the entity on the source. That is the primary key, or the logical key that you set in Field mapping.
-
The Control Plane fills the key in for you and asks for at least one key column (At least one comparison key is required).
-
A run that has no key, for example one started from the REST API or from Chronos on an entity with no key, is refused with
No comparison key provided for entity '<entity id>'.
What to do:
-
Give the entity a key before you validate it. Set a logical key on columns that are unique and never
NULL, or on IBM i use the relative record number (_RRN). See Choose keys for tables without a primary key. -
Check the key. Start a run with Validate key uniqueness on. The run fails with
DuplicateComparisonKeyif the key is not unique on either side. -
Read the Duplicate keys and NULL keys counters of every run. Validator reports those rows and does not fix them. See Differences in the grid.
A key can still stop the run after you set it:
-
The key columns must have the same ordering on both sides. If the types differ, for example a binary column on the source and a text column on the target, the run fails with
SchemaIncompatibleand a message such asComparison key column '<name>' has unsupported key type ('<source type>' / '<target type>') for merge-join ordering. Align the types, choose another key, or set an ordering expression for each side under Advanced: query filters (orderBySource,orderByTarget). A text key needs an expression that casts the text side. -
A key column that a field function writes holds different values on the two sides. Validator refuses it. Choose a key that no field function writes.
Sizing for big tables
Validator does not load a table into memory. It reads the source and the target in pages, in key order, and compares the pages as it goes. Memory use follows the page size, not the table size. These limits apply to a run:
| Limit | Default | Maximum | Where |
|---|---|---|---|
Rows per page ( |
10000 |
50000 |
REST API option |
Max runtime (seconds) |
3600 |
86400 |
Validator options, General, Limits |
Max differences |
10000 |
50000 |
Validator options, General, Limits |
Comparison jobs at the same time on Core Hub |
5 |
5 |
Fixed |
Active runs per entity |
1 |
1 |
Fixed |
What to do for a large table:
-
Run a Count only run first. It reads no row and tells you whether the counts match. See Statuses in the Control Plane.
-
Raise Max runtime (seconds) before the first full run. A run that exceeds it fails with
QUERY_TIMEOUT. See [query-timeout]. -
Narrow the rows with a
WHEREcondition on each side. Validator reads each table in one pass in key order. It does not split a table into parts, so a filter on a key range is how you compare a big table in slices. -
Index the key columns on both sides. The Reader warning notice names an index that speeds a run up when it has one to suggest.
-
Skip BLOB / CLOB columns, which is the default, to keep the pages small.
-
Do not run a large manual run and a large scheduled job on the same entity at the same time. Spread large jobs over time so that fewer than five run together. See [concurrency-conflict].
-
For a scheduled job, a run of one entity waits at most
SCHEDULER_VALIDATION_TIMEOUT_SECONDS(3600 by default). Raise it together with Max runtime (seconds). See Schedule validation.
Troubleshooting
After each fix, start a new run. A run does not refresh itself, so an old failed run stays on the screen until you do. The fix works when the new run ends as Completed, or as Completed with warnings with the counters you expect.
| Problem | Possible cause | What to do |
|---|---|---|
A run on an IBM i source fails with |
On IBM i, |
Upgrade Core Hub to the latest Gluesync 2.3 release, which reads the relative record number the way Db2 for i expects. Then start a new run on the entity. If the error stays, check that the run you are reading is the new one, not an old failed run. To use |
A run fails with |
The source returned its text keys in a different order than the order Validator expects, so the merge of the two sides cannot continue. |
Upgrade Core Hub to the latest Gluesync 2.3 release. It orders the text keys the same way on both sides. Each run then shows a Reader warning notice that the key column is ordered with a forced binary collation. This notice is expected. The warning also names an index you can create to make the run faster. |
A run fails with |
The mapping of the entity names a column that the target table does not have. This happens when the column was dropped or renamed on the target, or when the mapping points to the wrong name. |
Check on the target database that the column exists. If it does not, add it, or change the mapping of the entity so that the column points to an existing target column. Then run Validate again. |
A Count only run reads No differences found while the source and the target hold different numbers of rows |
The run used an older Core Hub that ended a count-only run as Completed whatever the counts were. |
Upgrade Core Hub to the latest Gluesync 2.3 release. A count-only run with different counts then ends as Completed with warnings and the message gives both counts and their difference. On the older release, read Source rows and Target rows in the run summary: they show the mismatch even when the status is Completed. To list the rows that differ, run a full validation without Count only. |
Rows that differ lists date and time columns where the target value is a small amount of time away from the source, for example one second |
The two databases store time with a different precision, and the run compares the values as they are. |
Open Validator options. On Columns & rules, search for the column and, under Date & time, choose how to match: Normalize to UTC, Exact match, Ignore fractions of a second, Ignore time, compare date only, or Ignore date and time columns. On Matching, set Comparison profile to Lenient or Strict, and set Temporal precision, the finest unit of time that is compared. Then start a new run and read Rows that differ and Notices. |
After an upgrade, Validate on an entity opens a page that stays on the loading logo (the Validate page does not load). The server logs show no error. |
Validate opens Validator in a new tab at |
In the tab that stays on the logo, reload without the cache once: press Ctrl+F5 on Windows and Linux, or Cmd+Shift+R on a Mac. If the page still hangs, clear the cached images and files of the site in the browser settings, or open the developer tools with F12, right-click the reload button, and choose Empty cache and hard reload. You can also open Validator from the side navigation or from the entity row, which do not reload the page. Do this once per browser. Core Hub releases after this problem was found tell the browser to check the version of the page each time, so the cached copy is not reused after an upgrade. |
A run on an IBM i source, or a scheduled Validate job, fails at once with |
Db2 for i has a query time limit. The Predictive Query Governor refuses a query up front when its estimated runtime is above the limit, and it does not run the query. Older builds handed the query timeout of the run (Max runtime (seconds), 3600 by default) to the governor. A validation of a large table fails before it reads a row. |
Upgrade Core Hub to the latest Gluesync 2.3 release. It cancels a query on wall-clock time when the timeout is reached, so the run starts and compares the table. Then start a new run. If a run still stops with a timeout, see the row about |
A run fails with |
The run needed more time than Max runtime (seconds). The default is 3600 seconds and the maximum is 86400. |
In Validator options, General, Limits, raise Max runtime (seconds). For a large table, narrow the rows with a |
A scheduled Validate job on many entities ends with a red Last run mark and no error text, or Run now leaves the page frozen, and the entities after the first one were not validated |
Entities of one job run one after another. The first entity that fails, or finds differences with Reconcile differences off, fails the job. The later entities of that run are not started. Three things hide the cause. First, Run now holds one HTTP request open for the whole job, so behind a proxy or ingress with a short timeout (60 seconds is common) the interface gets a gateway timeout while the job keeps running. Second, a second Run now while the first still runs starts an overlapping run of the same entities, which fails with |
Read the error of each entity run in Validator: pick the pipeline and the entity, and read Run history. Hover over the status of a failed run, or select it, to read the error code and the text. The hover text of the Last run mark can be empty in some releases. The error is still in Run history. Do not click Run now a second time: wait for the job to end. Raise the timeout of the proxy in front of Core Hub above the length of the job, or split a large job into several jobs of a few entities each, scheduled apart. Fix the failing entity, or remove it from the job, and run the job again. See Schedule validation for how a job treats differences. |
Validator refuses to start with |
Only one run can be active for an entity, and Core Hub runs at most five comparison jobs at the same time. A schedule that overlaps a manual run, or two jobs that validate the same entity, start a second run for the same entity. |
Wait for the active run to end, or select Cancel run on it, then start a new one. Spread large scheduled jobs so that they do not overlap. |
Data Validation is not available for this pipeline, or a run fails with |
The source or the target connector of the pipeline cannot compare data. |
Validator cannot compare that pair. Use Count both on the entity detail page and Query Studio to check the counts and the data. See Find and fix row differences between source and target. |