Scan Outcomes¶
DO Running scans
Reading scan outcomes
A Scan ends in one of three states: Success, Failure, or Aborted. This page explains how that outcome is decided, what "success with warnings" means, which situations produce a warning or a failure, and which fields to read when a dashboard or a Flow needs to act on the result.
The rules below apply to the Scan operation. For the states every Run shares, see Run States. For the resolution steps behind specific errors, see Scan Troubleshooting.
Three layers of results¶
A Scan records a result at three levels, and each level rolls up into the next:
| Layer | What it covers | Possible results | Where you see it |
|---|---|---|---|
| Partition | One slice of a container the scan read and evaluated. A container with a single partition still records one. The metadata checks of a container run against a virtual partition. | success, failure |
The Partitions sub-tab of a container card on the Run Results tab, with a Passed, Completed with warnings, or Failed status dot. |
| Container | One table, view, file pattern, or computed asset the scan targeted. | success, failure, aborted |
The container card on the Run Results tab, with a Success, Success with warnings, or Failed status dot. |
| Run | The whole Scan operation. | success, failure, aborted |
The status badge on the Run row of the Activity tab and on the Run's detail page. |
Each layer also carries a message: free text that gathers what went wrong, or what is worth knowing, at that level. The message is what turns a plain Success into "success with warnings", as described below.
How the outcome is decided¶
Partition result¶
A partition ends in failure when it could not be read or evaluated: the source refused or interrupted the read, the data could not be processed, or a check threw an error that could not be isolated to that check. Otherwise it ends in success. Anomalies found by the checks do not fail a partition. A partition whose checks flagged a thousand records still counts as a successful partition.
Container result¶
A container ends in failure when any of its partitions failed, or when the container itself could not be processed, for example because it could not be loaded at all. Otherwise it ends in success.
A container ends in aborted when the Run was stopped before the container's scan started. A container that was in progress when the Run was stopped is recorded as failed, with a message saying its heartbeat was lost, because its scan could not finish.
Run result¶
The Run result follows a strict precedence over its containers:
- Aborted if any container was aborted, which is what happens when a user stops the Run, or when the platform stopped it.
- Failure if any container failed, or if the operation itself failed outside of a container (for example, the operation ran past its time limit, or an unexpected error stopped it before every container was processed).
- Success otherwise.
So a single failed container is enough to end the whole Run in Failure, even when every other container succeeded. The successful containers keep their own results and anomalies: the Run Results tab lists them normally, and only the failed container shows a red dot.
Anomalies never fail a Scan
A Scan that finds anomalies is a successful Scan. The result reflects whether the platform could read and evaluate the data, not whether the data passed its checks. To act on anomalies, use the anomaly counts on the Run and its containers, or an Anomaly Detected trigger.
Success with warnings¶
"Success with warnings" is not a fourth state. The result stays success. What changes is that the Run, the container, or the partition carries a message. The UI reads that message as a warning:
| Level | Shown as |
|---|---|
| Run | An amber icon next to the Run ID on the Activity tab, with the tooltip Completed with logs, and a This operation reported a warning card in the Logs section of the Run's Overview tab. |
| Container | An amber status dot with the tooltip Success with warnings on the container card, and the message itself in a log block when the card is expanded. |
| Partition | An amber status dot with the tooltip Completed with warnings on the partition row. |
A warning on one level does not propagate upward on its own. In particular, the message of a successful container is never copied into the Run's message. A Run whose containers all succeeded with warnings shows a plain green Success on the Activity tab, and the amber dots live on the Run Results tab. The Run-level warning icon appears only when the operation itself recorded a message, such as an advisory that applies to the whole Run.
What produces a warning¶
The table lists the situations that leave a message on a successful container or partition. The wording of each message can change between releases, so treat the descriptions as the stable part, not the text.
| Situation | Level | What the message says | What to do |
|---|---|---|---|
| No active checks to assert. The container had no active quality check in the categories the scan selected, so its scan was skipped. | Container | The scan of the container was skipped because no active quality checks were asserted. | Nothing, unless the container was expected to have checks. Activate or create checks for it. |
| No data loaded. The read returned no records (an empty table, a file pattern that matched nothing, or an Incremental scan with no new records), so the checks had nothing to evaluate. | Container | No data was loaded from the container, so some checks were not asserted. | Confirm the container really is empty for this scan's read strategy. For an Incremental scan, this is expected when nothing arrived since the last scan. |
| A check could not be asserted. One or more checks could not be evaluated: a filter with invalid syntax, a field the check references that no longer exists, a check whose expression fails on the data it meets (for example, a comparison that cannot be applied to the field's type), or any other reason the platform could not evaluate the rule. The other checks on the container still run. | Partition and container | Not all requested checks could be asserted. | Open the Checks sub-tab of the container card, filter by Not Asserted, and fix the check. See Check results for how these checks are reported. |
| The enrichment write failed. The checks ran and the anomalies were identified, but they, the source records, or the remediation data could not be written to the enrichment destination. | Partition and container | Unable to write anomalies (or remediation data) to the destination table, with the destination's error. | Check the enrichment datastore's connection and permissions. The anomalies are still recorded in Qualytics. Only the enrichment copy is missing. |
| A read advisory. The source was read, but something about the read is worth knowing: column names had to be corrected from a data file, a file's header names differ from the catalog, files too short to hold a row were left out, a whole-number value exceeded the 64-bit range so the container's whole-number columns were read as decimals, or the partition filter could not be answered so every partition was read. | Container | A short code followed by a sentence describing what was noticed, for example header_names_differ. |
Usually nothing. The scan result is correct. The advisory explains an unexpected column name or type, or a scan that took longer than usual. |
Which advisories a datastore can raise depends on its type. The column, file, and partition filter advisories come from Hive datastores, and the whole-number advisory comes from Snowflake. Most Scans raise none.
Failure¶
What fails a container¶
A container fails when the platform could not read or evaluate it. The common situations, each of which produces a classified error described in Failure classification:
- The connection to the source was refused, timed out, or was interrupted while reading.
- The credentials were rejected or have expired, or the connection lacks permission on the table or file.
- The table, view, or file no longer exists, or a referenced column was renamed or dropped.
- The container is marked Unloadable after failing in three consecutive scan or profile operations. See Unloadable Container Error.
- The SQL of a computed table, computed file, or computed join, or a check expression that could not be isolated, is invalid for the data it meets.
- The source could not convert a value to its declared type, or returned a malformed record.
- The platform ran out of memory or disk while processing the container.
What fails the Run without a failed container¶
A few situations end the Run in Failure even though no container card shows a failure:
- The operation ran past its time limit. The message states that the operation timed out and after how long.
- An unexpected error stopped the operation before every container was processed. The containers that had already finished keep their results.
- A scheduled scan has no active check left to assert. The Run fails as soon as it starts. See A Scheduled Scan Fails Over Its Selected Checks.
The Run's failure message¶
When containers failed, the Run's message leads with a count, such as "2 container(s) failed", followed by the message of each failed container, each prefixed with the container's name. When many containers failed, the message keeps a representative set and states how many additional failures were omitted. The full list is always available container by container on the Run Results tab. The message of a successful container is never included.
On the Run's Overview tab, the Logs section shows the failure as an error card that leads with the classified title and guidance, with the raw message behind the card's Details toggle.
Failure classification¶
Every failed Scan carries a classification alongside its message. It is built by the platform from what it knows about the failure, and it is designed to be stable where the raw message is not. The same classification appears on the Run's Overview tab, as the title and guidance of the error card, and through the API, as the error_code, fault_domain, and phase fields of the operation and its fault_context object.
The list changes over time
The platform adds codes and adjusts which situations map to which code as new sources and failure modes are understood. Do not treat this list as a contract: build logic on the fields described in Reading outcomes through the API, and expect codes you have not seen before. Not every datastore can raise every code, so the codes a given deployment sees are a subset of the list.
The fault_domain says which system the failure belongs to:
| Fault domain | Meaning |
|---|---|
source_datastore |
The source system refused, interrupted, or could not complete the read. The fix is usually on the source side or in the datastore connection. |
misconfiguration |
Something configured in Qualytics is invalid: a computed asset's SQL, a check expression, a credential's format, or a missing setting. The fix is in Qualytics. |
dataplane |
The platform's own processing engine could not complete the work, typically for lack of capacity. Retrying usually succeeds, and a persistent one is a sizing question for the administrator. |
unknown |
The failure could not be classified. |
The source datastore codes a Scan can carry, with the title and guidance the UI shows for each, and whether retrying the same scan is likely to succeed. These are the failures that come from reading the customer's own system, which is where most Scan failures originate and where a downstream team can act:
| Code | Title | Guidance | Retry |
|---|---|---|---|
SOURCE_AUTH_FAILED |
Datastore authentication failed | The credentials were not accepted. Check that the username/password, key, or token is correct and the account is not locked, then validate the connection. | No |
SOURCE_CREDENTIALS_EXPIRED |
Your datastore credentials have expired | Rotate or regenerate the credentials (token, key, or password), update them in the datastore connection, then validate the connection. | No |
SOURCE_TLS_INVALID |
TLS/SSL connection to your datastore failed | Verify the server certificate is valid and trusted (not expired or revoked) and that TLS settings match, then validate the connection. | No |
SOURCE_UNREACHABLE |
Could not reach your datastore | Check the hostname, port, firewall/allow-listing, and network route from your deployment, then validate the connection. | Yes |
SOURCE_CONNECTION_INTERRUPTED |
The connection to your datastore was interrupted | The source ended the connection while Qualytics was reading data, often due to a server-side session kill or a maintenance/ETL window. Retry the operation; if it recurs, schedule scans outside the source's maintenance window. | Yes |
SOURCE_TIMEOUT_LOAD |
Timed out reading from your source datastore | Your source datastore may be under load. Check its availability and try again. | Yes |
SOURCE_TIMEOUT_SINGLE_RECORD |
Timed out reading a record from your source | Your source datastore timed out while reading a record. It may be under load, so try again shortly. | Yes |
SOURCE_PERMISSION_DENIED |
Permission denied by your source datastore | The connection lacks permission for the requested object. Grant access to it, then try again. | No |
SOURCE_OBJECT_NOT_FOUND |
A table, file, or column is missing | It may have been renamed, moved, or dropped. Re-sync the datastore so Qualytics picks up the current schema. | No |
SOURCE_CONTAINER_UNLOADABLE |
This asset is paused after repeated load failures | Qualytics stopped loading this asset because it failed repeatedly. Check the technical details for guidance on restoring access, then re-run the operation. | No |
SOURCE_WAREHOUSE_INACTIVE |
No active warehouse is available | Resume or assign a warehouse for the connection, then retry. | Yes |
SOURCE_QUERY_CANCELED |
Your source datastore canceled the query | It may be undersized or overloaded. Please retry. | Yes |
SOURCE_QUOTA_EXCEEDED |
Source quota or rate limit reached | Your source datastore reported a quota or rate limit. Wait for it to reset, then retry. | Yes |
SOURCE_TYPE_CONVERSION |
A value in your source data does not match its declared type | A column is declared with a type too narrow for a value it contains (for example an INTEGER column holding a larger number). Correct the column type in your source query, view, or external table, then retry. | No |
SOURCE_MALFORMED_RECORD |
A malformed record was found in your source data | A record could not be parsed while reading your source data. Correct the record or its format, then retry. | No |
SOURCE_RESPONSE_TOO_LARGE |
The source response was too large to process | A temporary dataset or a narrower query usually resolves this. | No |
SOURCE_INTERNAL_ERROR |
Your source datastore reported an internal error | This is usually transient. Please retry. | Yes |
SOURCE_UNKNOWN |
Problem reading from your source datastore | There was a problem reading from your source datastore. Please check it and try again. | Yes |
A failure in the other fault domains carries a code of its own family, with the same title and guidance structure, and the UI and the API present it the same way. When the platform cannot pin a failure to a specific code, it still reports the fault domain with that domain's generic code (for example SOURCE_UNKNOWN), so fault_domain is the more dependable field for coarse routing and code the more specific one when it is available.
The raw message under the classification is the technical detail: the text the source, its driver, or the platform produced when the failure happened. It is the right thing to show a person investigating the failure and the wrong thing to match on in automation, because its wording depends on the source and changes between releases.
Aborted¶
A Run ends in Aborted when a user stops it with Abort, or when the platform stops it, for example because the processing engine became unavailable before every container was scanned. Containers that had not started are recorded as aborted, with a message saying their scan was skipped because the operation was aborted, and containers that had finished keep their results. An Aborted Run can be resumed. See Available Actions.
An Aborted Run carries no failure classification: error_code and fault_domain are empty, because stopping a Run is not a fault.
Check results¶
Within a successful or failed container, each check has its own result for the scan, independent of the container's result:
| Check result | Meaning |
|---|---|
| Passed | The check was evaluated and produced no anomaly. |
| Failed | The check was evaluated and produced at least one anomaly. |
| Not Asserted | The check could not be evaluated in any partition of the container, so it produced no anomalies, but it did not pass either. |
A check that is not asserted does not fail the container: the container succeeds with a warning, and its card shows a Checks Not Asserted count next to the passed and failed counts. Read a check's result rather than its anomaly count: a check that was not asserted also has zero anomalies.
Reading outcomes through the API¶
A dashboard or an external system should drive its logic from the result fields, which are stable, and never from the message text, which is not. The fields, from the top down:
| Object | Endpoint | Fields to read |
|---|---|---|
| Run | GET /api/operations/{id} |
result (success, failure, aborted, or running while in progress), message, and on a failure error_code, fault_domain, phase, and the fault_context object with the title, hint, who, and retryable fields described on the Status API page. |
| Container scan, with check counts | GET /api/operations/{id}/containers (as container_scan on each item) |
result, message, anomaly_count, passed_checks_count, failed_checks_count, and unasserted_checks_count. |
| Container scan, with partitions | GET /api/container-scans/{id} |
result, message, and anomaly_count for the container, plus partition_scans. This endpoint does not return the check counts. |
| Partition scan | GET /api/container-scans/{id} (as partition_scans) |
result and message per partition, with records_processed and anomaly_count. |
| Check results | GET /api/operations/{id}/scan-checks or GET /api/container-scans/{id}/checks |
scan_result (passed, failed, or unasserted) and scan_anomaly_count per check. See List Check Results for a Scan. |
The rules for reading them:
- Success with warnings at any level is
result == "success"with a non-emptymessage. There is no separate value for it. - Did the data pass? is a different question from did the scan succeed? Answer the first with the anomaly counts and the check results, and the second with
result. - Should we retry? Read
fault_context.retryableon a failed Run. It is the platform's own judgment of whether the same scan is likely to succeed if run again, so it stays correct as codes are added. - Route by
fault_domainwhen deciding who should look at a failure, and bycodewhen a specific situation needs specific handling. Expect new codes. - A Flow's Operation Completed trigger matches on the Run's
result. Its Operation Status filter offers Success and Failure, a Run that succeeded with warnings matches Success, and an aborted Run never starts the Flow. See Flow Triggers and, for a way to be told about warnings, the Flow Actions FAQ.
Keep the message for people
message is still the best thing to put in a notification or a ticket. It names the containers that failed and carries the source's own explanation. Just do not branch on it.