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
| Requirement | Details | Refusal |
|---|---|---|
| Keys | Every table with a rule has a primary key or a unique key. | processing_requires_source_key, processing_unique_key_required |
| Apply errors | The target stops on an apply error. The applyErrorPolicy values skip and deadletter, and dead-letter files, are refused. | processing_requires_fail_policy |
| SQL Server source | ALLOW_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 keys | The source login has VIEW DEFINITION on the database when selected tables have foreign keys. | processing_fk_catalog_view_definition_required |
| Oracle source | The source login has SELECT ANY DICTIONARY. | processing_fk_catalog_dictionary_visibility_required |
| Agents | Every 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_requiredwhenREAD_COMMITTED_SNAPSHOTis on butALLOW_SNAPSHOT_ISOLATIONis off;repair_source_row_versioning_requiredwhen 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
- 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.
- Test rule. In the wizard, Test rule checks each rule against the source schema and reports problems per table. See Overview: Test a rule.
- 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.
- 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.
- 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
| Limit | Value |
|---|---|
| Table rules per target | 10,000 |
| Size of one target's rules | 1 MiB as JSON |
| One expression | 8,192 UTF-8 bytes. A table's condition and the All-tables condition together also count against it. |
| Expression complexity | 256 nodes, nested at most 32 levels deep |
| Output columns | 4,096 across the All-tables lists and every table's list |
| Output name | 1,024 characters, no control characters |
IN list | 128 literals |
| Text value inside an expression | 1,048,576 characters |
| Exact numbers | 38 digits, scale up to 38 |
| Masking keys | 64 per target; alias and version up to 128 characters; reference up to 1,024 characters |
| Key size of a masking key | 32 to 4,096 bytes |
| Test rule sample | 1 to 100,000 rows per table |
Messages in the Configure dialog
| Message | Fix |
|---|---|
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
| Message | Cause |
|---|---|
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.
| Code | Meaning | Example |
|---|---|---|
invalid-expression | The text isn't one valid expression in the source's SQL dialect. | amount > |
scalar-expression-only | The expression contains a query, FROM, aggregate, TOP, DISTINCT or another clause. | |
expression-size, expression-complexity | The expression is too long or too deeply nested. | |
unknown-column, qualified-column, ambiguous-column | A 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-modifier | The 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-arity | The 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-required | An 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-scale | The 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-types | An 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-boolean | A condition doesn't produce true or false. | |
numeric-scale-overflow | A multiplication would need more than 38 decimal places. | fx_rate * fx_rate, where fx_rate is decimal(38,20) |
case-arity | A 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-required | A 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-unsupported | A vector function has invalid arguments. | VECTOR_DISTANCE('manhattan', embedding, centroid) |
temporal-expression-type-unsupported | A date and time result of CASE or COALESCE has a type that can't be carried exactly. | |
protected-column-missing-or-transformed, protected-column-alias | A 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-collision | Two output columns have the same target name. | Email and email |
processing_source_predicate_unsupported | A 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-lob | A 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.
| Code | Cause | Example |
|---|---|---|
numeric-overflow, numeric-overflow-or-rounding | A 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-fraction | A 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-failed | A whole number cast to INT, SMALLINT or TINYINT is out of that type's range. | CAST(order_count AS SMALLINT) on 40000 |
invalid-number | Text cast to a number isn't a plain decimal number. | CAST(amount_text AS DECIMAL(12,2)) on '1,200.00' |
string-overflow | Text 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-cast | Text 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-mismatch | Two date and time values of different kinds were compared. | |
mask-input-size | A value to hash is larger than the mask accepts. | |
processing_lob_scalar_limit | A large value is too long for an operation that needs the whole value at once. | |
processing_lob_stream_operation_unsupported | A value over 1 MiB reaches an operation that can't handle it. See Output and computed columns. | |
processing_retained_byte_budget | The 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"
}
}
}