In-flight processing

Validation and limits

Check what processing rules need, when they are validated, every limit, and what each validation message means.

SQL Flow checks processing rules before any row moves, and refuses a rule it can't apply exactly rather than approximating it. This page lists the requirements, the limits and the messages you can see.

Requirements

RequirementDetailsRefusal
KeysEvery table with a rule has a primary key or a unique key.processing_requires_source_key, processing_unique_key_required
Apply errorsThe target stops on an apply error. The applyErrorPolicy values skip and deadletter, and dead-letter files, are refused.processing_requires_fail_policy
SQL Server sourceALLOW_SNAPSHOT_ISOLATION is on, or the database is read-only. See Snapshot isolation.repair_source_snapshot_isolation_required, repair_source_row_versioning_required
SQL Server foreign keysThe source login has VIEW DEFINITION on the database when selected tables have foreign keys.processing_fk_catalog_view_definition_required
Oracle sourceThe source login has SELECT ANY DICTIONARY.processing_fk_catalog_dictionary_visibility_required
AgentsEvery agent that runs the pipeline supports the rule format.See Saving rules on an existing pipeline.

Snapshot isolation on SQL Server sources

After a crash, a pipeline with rules repairs the rows it may have left half-applied, reading the source under snapshot isolation so it takes no locks. The wizard's Prepare step and the start therefore refuse a SQL Server source where snapshot isolation is off. The refusal starts with:

  • repair_source_snapshot_isolation_required when READ_COMMITTED_SNAPSHOT is on but ALLOW_SNAPSHOT_ISOLATION is off;
  • repair_source_row_versioning_required when neither is on.

SQL Flow never changes the setting itself. Turn it on, replacing <database_name>:

ALTER DATABASE [<database_name>] SET ALLOW_SNAPSHOT_ISOLATION ON;

When rules are checked

  1. While you type. The Configure dialog checks sizes, names and required fields. A table with a problem shows it in red in the table list, and Save or Done selects the table and shows the reason.
  2. Test rule. In the wizard, Test rule checks each rule against the source schema and reports problems per table. See Overview: Test a rule.
  3. Prepare and start. Prepare target schema, and the pipeline start, check every rule against the source schema. A rule that fails is refused with its code, and nothing is created or moved.
  4. Each row. Some problems depend on values, such as a cast that would round. They stop the pipeline when the row is processed. See Row errors.
  5. Source schema changes. A schema change on a table that a rule covers holds the covered tables until you reload the pipeline. See Schema changes.

Limits

LimitValue
Table rules per target10,000
Size of one target's rules1 MiB as JSON
One expression8,192 UTF-8 bytes. A table's condition and the All-tables condition together also count against it.
Expression complexity256 nodes, nested at most 32 levels deep
Output columns4,096 across the All-tables lists and every table's list
Output name1,024 characters, no control characters
IN list128 literals
Text value inside an expression1,048,576 characters
Exact numbers38 digits, scale up to 38
Masking keys64 per target; alias and version up to 128 characters; reference up to 1,024 characters
Key size of a masking key32 to 4,096 bytes
Test rule sample1 to 100,000 rows per table

Messages in the Configure dialog

MessageFix
Enter a row condition of at most 8,192 UTF-8 bytes.Shorten the condition.
Choose at least one output column, including the source keys.Add columns to the list, or untick Choose output columns.
Enter an output name for every column.Fill in each Output name.
Use a different output name for each column.Rename a duplicate output.
Enter a source expression for every output column.Fill in each Source expression.
Keep this source column or clear the field.Select Keep source column or clear Source column to keep.
Global output columns: …, Global column masks: …The All-tables list has the problem named after the colon.
Use at most 10,000 table rules.Reduce the number of tables with rules.
Use at most 1 MiB of data processing rules.Simplify the rules.
Use at most 4,096 output columns across global and selected table rules.Shorten the output lists.
Use at most 64 masking key references.Use fewer key aliases.
Use a masking key alias of at most 128 letters, digits, dots, hyphens or underscores.Rename the alias in HASH_MASK.
<alias>: enter the masking key version and operator secret reference.Fill in both fields under All tables. See Masking.
<alias>: enter the immutable masking key version., <alias>: enter the operator secret reference.Fill in the named field.
This table is no longer replicated. Reset it to remove its settings before saving.Select Reset table on that table.
The saved data processing rules are invalid.The stored rules can't be read. Reopen Configure and set the rules again.

Saving rules on an existing pipeline

MessageCause
Restore this pipeline before editing processing rules.The pipeline is archived.
Assign this pipeline before saving processing rules.No agent runs the pipeline.
Every pipeline runner must be registered and online before Reload.An agent of the pipeline is offline.
Upgrade every pipeline runner to support these processing rules before Reload.An agent is too old for these rules.
Global rules require the matching processing contract on the capture agent, each affected target owner and their standby. Upgrade the agent first.An agent, or its standby, is too old for All-tables rules.
Wait for the pipeline's outstanding command to finish before saving rules.Another command, such as a pause, is still running.
The pipeline configuration changed. Reopen the editor before saving.Someone changed the pipeline after you opened Configure.
The pipeline's current runner ownership changed. Reopen the editor.Another agent took over a role of the pipeline.
This target no longer exists.The target was removed.
Names saved. The rules were changed elsewhere since you opened Configure; close it and open it again to see them.The names were saved, but the rules changed meanwhile.

Expression errors

A rule problem is reported as a code followed by where it is, for example unsupported-function at expression. Test rule shows the code alone. The examples are written in T-SQL for a SQL Server source.

CodeMeaningExample
invalid-expressionThe text isn't one valid expression in the source's SQL dialect.amount >
scalar-expression-onlyThe expression contains a query, FROM, aggregate, TOP, DISTINCT or another clause.
expression-size, expression-complexityThe expression is too long or too deeply nested.
unknown-column, qualified-column, ambiguous-columnA column name doesn't exist, is qualified, or matches two columns that differ only by case.amont > 0, o.amount > 0
unsupported-expression, unsupported-operator, unsupported-unary, unsupported-expression-modifierThe construct isn't in the Expression reference.CONVERT(INT, amount_text), amount / 2 > 10, amount COLLATE Latin1_General_BIN2 = 1
unsupported-function, unsupported-function-form, function-arityThe function isn't supported, is called in an unsupported form, or has the wrong number of arguments.LEN(last_name) > 3, dbo.fn_region(region_id) = 'EU', CONCAT(first_name, ' ', last_name)
unsupported-in-list, in-literal-requiredAn IN list holds a query, more than 128 items, or a non-literal.region_id IN (home_region_id, 2)
unsupported-cast, invalid-cast-facets, cast-scaleThe cast's type or size isn't supported.TRY_CAST(amount_text AS INT), CAST(amount AS DECIMAL(40,2))
boolean-type, numeric-type, string-type, opaque-expression-type, incompatible-expression-typesAn operand has the wrong type, such as text compared with a number.status = 42, first_name + last_name, UPPER(order_id), quantity as a row condition
predicate-must-be-booleanA condition doesn't produce true or false.
numeric-scale-overflowA multiplication would need more than 38 decimal places.fx_rate * fx_rate, where fx_rate is decimal(38,20)
case-arityA CASE expression is malformed.
mask-in-predicate, mask-length, mask-constant-count-required, mask-key-alias-constant-required, mask-key-alias-invalid, mask-input-type, redact-constant-required, immutable-mask-key-version-requiredA mask is used in a condition, or has invalid arguments. See Masking.PARTIAL_MASK(email, -1, 3), HASH(email)
vector-type-required, vector-shape-mismatch, vector-selector-constant-required, vector-selector-invalid, vector-function-base-type-unsupportedA vector function has invalid arguments.VECTOR_DISTANCE('manhattan', embedding, centroid)
temporal-expression-type-unsupportedA date and time result of CASE or COALESCE has a type that can't be carried exactly.
protected-column-missing-or-transformed, protected-column-aliasA key, unique or foreign key column is missing, computed or renamed in the output list.Output name id for the key column customer_id
output-name-collisionTwo output columns have the same target name.Email and email
processing_source_predicate_unsupportedA condition can't run in the source query of the initial load. See Row filtering.LOWER(email) = 'ada@example.com' as a row condition
processing-computed-output-requires-lobA long computed text column can't be written as a large value.
processing_derived_source_unsupported, generated-*A rule reads a computed source column that SQL Flow can't evaluate.
processing_filter_foreign_key_*, processing_fk_catalog_*A foreign key relationship blocks the filter. See Row filtering.

Row errors

These codes stop the pipeline when a row's value can't be processed exactly. The expression is accepted at the start, and the pipeline stops when it processes the example value.

CodeCauseExample
numeric-overflow, numeric-overflow-or-roundingA number doesn't fit its type without rounding.CAST(amount AS DECIMAL(5,2)) on 1234.50; CAST(unit_price * 1.2 AS DECIMAL(18,2)) on 9.99 (11.988)
integer-overflow-or-fractionA value cast to an integer has a fraction, or is out of the range of BIGINT.CAST(unit_price AS INT) on 9.99
scalar-evaluation-failedA whole number cast to INT, SMALLINT or TINYINT is out of that type's range.CAST(order_count AS SMALLINT) on 40000
invalid-numberText cast to a number isn't a plain decimal number.CAST(amount_text AS DECIMAL(12,2)) on '1,200.00'
string-overflowText is longer than its cast length, or than 1,048,576 characters.CAST(code AS VARCHAR(3)) on 'ABCD'
boolean-cast, datetime-cast, datetime-offset-castText cast to BIT or a date and time isn't in the accepted form.CAST(flag_text AS BIT) on 'TRUE'; CAST(shipped_text AS DATETIME2) on '2024-05-01 13:45'
datetime-kind-mismatchTwo date and time values of different kinds were compared.
mask-input-sizeA value to hash is larger than the mask accepts.
processing_lob_scalar_limitA large value is too long for an operation that needs the whole value at once.
processing_lob_stream_operation_unsupportedA value over 1 MiB reaches an operation that can't handle it. See Output and computed columns.
processing_retained_byte_budgetThe values of one batch need more memory than the agent allows for processing.

To recover, fix the rule or the data, save the rules, and let the pipeline reload.

Validate a rules file with the CLI

The CLI checks the structure of a rules file locally, without the source: the fields, the version, the table names, the sizes and the counts. It doesn't parse the expressions, so expression errors appear only in Test rule, in Prepare target schema and at the start. Replace <rules.json> with the file and list the source tables the pipeline replicates:

sqlflow processing validate --file <rules.json> --tables <schema.table>,<schema.table>

It prints Processing structure valid; source schema and runtime eligibility have not been checked. Use sqlflow processing describe with the same options to print a JSON summary instead.

A rules file uses the source table names as keys under tables. Set "version" to 1 for per-table rules only, 2 when you use globalPredicate, and 3 when you use globalColumns, globalMasks or maskKeys. This file uses every field:

{
  "version": 3,
  "globalPredicate": "TenantId IN (1, 2, 3)",
  "globalMasks": [
    { "name": "Email", "expression": "HASH_MASK(Email, 'customer')" }
  ],
  "maskKeys": {
    "customer": { "version": "v1", "secretRef": "env:CUSTOMER_MASK_V1" }
  },
  "tables": {
    "dbo.Orders": {
      "predicate": "status = 'active'",
      "columns": [
        { "name": "OrderId", "expression": "OrderId" },
        { "name": "Email", "expression": "HASH_MASK(Email, 'customer')" },
        { "name": "LineTotal", "expression": "CAST(Quantity * UnitPrice AS DECIMAL(18,2))" }
      ]
    },
    "dbo.Customers": {
      "predicate": "DeletedAt IS NULL"
    }
  }
}

See also

If this was useful,
our newsletter will be too.

Get monthly insights on data engineering, AI, and building critical infrastructure - direct from the Spectral Core team and CEO Damir Bulic.