What you will be able to do
- Configure automatic retries and auto-suspension for a failing task graph, and retry a failed run manually
- Use error notifications, event-table logging, TASK_HISTORY and QUERY_HISTORY to find out what failed and who ran it
- Audit reads and writes with ACCOUNT_USAGE.ACCESS_HISTORY
- Trace upstream and downstream impact with Snowsight data lineage and GET_LINEAGE
1.When a task fails: retries, suspension and recovery
A Snowflake pipeline is usually a task graph: a root task that holds the schedule, plus child tasks that run after it. A run counts as failed when the SQL in a task body raises a user error or times out. Runs that are skipped, canceled or that fail from a system error are treated as indeterminate. By default, one failed child task means the whole graph run has failed.
CREATE OR REPLACE TASK task_root
SCHEDULE = '1 MINUTE'
TASK_AUTO_RETRY_ATTEMPTS = 2 -- Failed task graph retries up to 2 times
SUSPEND_TASK_AFTER_NUM_FAILURES = 3 -- Task graph suspends after 3 consecutive failures
AS SELECT 1;| Control | Set on / run against | Effect |
|---|---|---|
| TASK_AUTO_RETRY_ATTEMPTS | Root task | Retries the entire graph immediately when a child task fails |
| SUSPEND_TASK_AFTER_NUM_FAILURES | Root task | Suspends the graph after N consecutive failures (default 10) |
| EXECUTE TASK ... RETRY LAST | Root task | Re-runs the latest graph run from the last failed task |
| EXECUTE TASK ... RETRY GRAPH RUN GROUP | Root task, with a GRAPH_RUN_GROUP_ID | Retries an older graph run |
| ALTER TASK ... SUSPEND | A child task | Skips that child; the graph continues as though it succeeded |
A finalizer task (CREATE TASK ... FINALIZE = <root>) runs after every other task in the graph has completed or failed. That makes it the natural place to send success or failure notifications and to clean up intermediate data. If the root task itself is skipped, the finalizer does not start. To change a task in a scheduled graph, suspend the root first. The current run finishes, and future runs are cancelled until you resume it.
Checkpoint 1 of 6· Check yourself
A nightly graph failed at its third child task, and the first two tasks are expensive. What re-runs the graph starting from the failed task?
RETRY LAST resumes the latest graph run from its last failed task. Auto-retry re-runs the whole graph, and the other two options change state or thresholds without re-running anything.
“attempt to run the task graph from the last failed task”Source: docs.snowflake.com
Checkpoint 2 of 6· Exam question
An auditor asks which physical tables were read when analysts queried the view `V_SALES_REPORT`, which joins three base tables. The account is on Enterprise Edition. Which approach returns the underlying tables rather than only the view that was named in each query?
Correct answer: D — Read the `BASE_OBJECTS_ACCESSED` column of `SNOWFLAKE.ACCOUNT_USAGE.ACCESS_HISTORY` and flatten it to list the underlying tables for each query.
- A. Incorrect. `DIRECT_OBJECTS_ACCESSED` lists only the objects named directly in the query, so a query on the view shows the view and not its base tables.
- B. Incorrect. `OBJECT_DEPENDENCIES` shows static definition-time references between objects; it holds no per-query or per-user access information.
- C. Incorrect. Matching query text is fragile and misses queries made through other views, and the `TABLES` view lists table metadata rather than who read what.
- D. Correct. `BASE_OBJECTS_ACCESSED` records the underlying tables and columns touched after views are resolved, which is what read-lineage requires.
2.Logging and monitoring task runs
Retries only help if someone learns that a run failed. Snowflake can push task error notifications through a notification integration that targets Amazon SNS, Google Pub/Sub or Azure Event Grid. You set ERROR_INTEGRATION on a standalone task or on the root of a graph, and failures in child tasks are reported through the root's integration. Delivery is at-least-once, so consumers must be able to handle duplicate messages. If TASK_AUTO_RETRY_ATTEMPTS is above 0, you get a notification for each failed run, retries included.
CREATE TASK mytask
SCHEDULE = '5 MINUTE'
ERROR_INTEGRATION = my_notification_int
AS
INSERT INTO mytable(ts) VALUES(CURRENT_TIMESTAMP);For logging, the task parameter LOG_LEVEL sets which events are ingested into the active event table. Events at that level and above are kept. For run history, the ACCOUNT_USAGE TASK_HISTORY view gives each completed run a STATE of SUCCEEDED, FAILED, CANCELLED or SKIPPED, and its QUERY_ID can be joined to QUERY_HISTORY. A run that times out always shows as FAILED. The view does not include scheduled or executing runs; for those, use the TASK_HISTORY table function in the Information Schema. To find out who ran a task, check QUERY_HISTORY: a task that did not run as an actual user shows SYSTEM.
Checkpoint 3 of 6· Check yourself
A task run hit USER_TASK_TIMEOUT_MS and was stopped. What STATE does the ACCOUNT_USAGE TASK_HISTORY view show for it?
Timed-out runs are always recorded as FAILED. EXECUTING never appears in this view, which lists completed runs only.
“The timed-out tasks always have a FAILED state in the task history.”Source: docs.snowflake.com
3.Auditing with ACCESS_HISTORY
Monitoring tells you that a run failed. Auditing tells you which data was read or written, and by whom. The ACCESS_HISTORY view in ACCOUNT_USAGE (also available in ORGANIZATION_USAGE) holds one row per SQL statement. It covers reads, and writes such as INSERT, UPDATE, DELETE and COPY. That direct link between user, query, object and column is what supports compliance audits, for example identifying who wrote to a table and when, for GDPR or CCPA.
| Column | Records |
|---|---|
| direct_objects_accessed | Objects named in the query, e.g. view_2 in SELECT * FROM view_2 |
| base_objects_accessed | The original source objects, e.g. base_table under view_2 |
| objects_modified | Write targets and the columns written, e.g. table_1 after a CTAS |
| object_modified_by_ddl | DDL on databases, schemas, tables, views and columns, including policy and tag changes |
| policies_referenced | Row access and masking policies on objects the query touched |
| parent_query_id / root_query_id | The calling query or stored procedure, including nested calls |
Pipelines often send several statements in a single request through the Python connector or the SQL API. In that case the request returns one query_id, which is really a parent ID. To get each statement, filter ACCESS_HISTORY on parent_query_id:
SELECT query_id, parent_query_id, direct_objects_accessed FROM snowflake.account_usage.access_history WHERE parent_query_id = 6789;Checkpoint 4 of 6· Check yourself
A user runs SELECT * FROM view_2, where view_2 reads view_1, which reads base_table. What does ACCESS_HISTORY record in base_objects_accessed?
view_2 goes in direct_objects_accessed. base_objects_accessed holds the original data source, and intermediate views are not listed.
“base_table in the base_objects_accessed column because that is the original source of the data in view_2.”Source: docs.snowflake.com
Checkpoint 5 of 6· Exam question
A staging column `order_date_raw` is VARCHAR and holds valid ISO dates, values such as `N/A`, and impossible dates like `2026-13-45`. The cleansing step must load every row, store NULL for unparseable dates, and send those rows to a reject table. Which expression meets this?
Correct answer: B — `TRY_TO_DATE(order_date_raw, 'YYYY-MM-DD')`, which returns NULL for unparseable values so those rows can be filtered into a reject table.
- A. Incorrect. `ON_ERROR` is a COPY option and not a session parameter for SELECT, and `TO_DATE` still raises an error on the first bad value.
- B. Correct. `TRY_TO_DATE` returns NULL instead of raising an error, so all rows load and the NULL results identify the records for the reject table.
- C. Incorrect. `COALESCE` runs only after `TO_DATE` has evaluated, so the conversion error is raised first, and a fallback date would hide bad rows anyway.
- D. Incorrect. The `CASE` handles only the literal `N/A`; an impossible value like `2026-13-45` still makes `CAST` fail, so the query errors out.
Sources6
4.Data lineage: tracing a bad value upstream and its impact downstream
When a report shows a bad number, lineage answers two questions: where did it come from (upstream), and what else is affected (downstream)? Snowflake tracks two kinds of relationship. Data movement covers statements such as COPY INTO, CTAS, INSERT ... SELECT, MERGE and UPDATE. Object dependencies cover cases where an object only references another, as a view references a table. In Snowsight, go to Catalog » Explorer, select an object and open the Lineage tab. You can then step one hop at a time upstream or downstream, or select an arrow to see the SQL that created the downstream object. Lineage created by a task or stored procedure shows that task or procedure on the arrow.
Column lineage goes down to individual columns. A column's Distance shows how many hops away a related column sits. In ACCESS_HISTORY, column lineage enriches objects_modified, which supports root-cause analysis of data-quality failures. It also helps you spread tags and masking policies to derived columns. Column lineage is not supported for semantic views. To query lineage in SQL, GET_LINEAGE (SNOWFLAKE.CORE) returns a subset of what the Lineage tab shows.
Checkpoint 6 of 6· Check yourself
Which of these creates an object-dependency relationship rather than a data-movement relationship in Snowflake lineage?
A view references its base table without copying data, so it is a dependency. CTAS, MERGE and COPY INTO move data.
“Object dependencies, when an object references a base object but does not materialize or copy data, such as when a view references a table.”Source: docs.snowflake.com
Exam traps
Each one states something that sounds right. Open it to see what is actually true.
1.Suspending a broken child task stops the downstream tasks that depend on it.Why is that wrong?
A suspended child task is skipped, and the graph carries on as though that task had succeeded.
Covered in When a task fails: retries, suspension and recovery
2.Each child task in a graph needs its own ERROR_INTEGRATION to report failures.Why is that wrong?
You set the integration on the root task only, and child task failures are reported through it.
Covered in Logging and monitoring task runs
3.Every query in QUERY_HISTORY also has a row in ACCESS_HISTORY.Why is that wrong?
Whether a statement gets an ACCESS_HISTORY row depends on its structure, so some QUERY_HISTORY entries have no match there.
Covered in Auditing with ACCESS_HISTORY
Sources
Every claim above is drawn from one of these pages, quoted as it was written on the date shown.
- 1.
“Failed task runs include runs in which the SQL code in the task body either produces a user error or times out.”
↩︎ When a task fails: retries, suspension and recovery“Specifies the severity level of events for this task that are ingested and made available in the active event table.”
↩︎ Logging and monitoring task runs - 2.
“By default, if a child task fails, the entire task graph is considered to have failed.”
↩︎ When a task fails: retries, suspension and recovery“By default, a task graph is suspended after 10 consecutive failures.”
↩︎ When a task fails: retries, suspension and recovery“Send notifications about task success or failure.”
↩︎ When a task fails: retries, suspension and recovery“When you suspend a child task, the task graph continues to run as though the child task had succeeded.”
↩︎ Exam trap 1“When a child task fails, the entire task graph is immediately retried, up to the number of times specified.”
↩︎ Prediction“attempt to run the task graph from the last failed task”
↩︎ Checkpoint - 3.
“Snowflake guarantees at-least-once message delivery of notifications”
↩︎ Logging and monitoring task runs - 4.
“Status of the completed task: SUCCEEDED, FAILED, CANCELLED, or SKIPPED.”
↩︎ Logging and monitoring task runs“The timed-out tasks always have a FAILED state in the task history.”
↩︎ Checkpoint - 5.
“To see who ran a task, use the QUERY_HISTORY view.”
↩︎ Logging and monitoring task runs - 6.
“Each row in the ACCESS_HISTORY view contains a single record per SQL statement.”
↩︎ Auditing with ACCESS_HISTORY“Identify the Snowflake user who performed a write operation on a table or stage and when the write operation occurred”
↩︎ Auditing with ACCESS_HISTORY“Column lineage provides a mechanism to trace the data to its source, which can help to pinpoint points of failure”
↩︎ Data lineage: tracing a bad value upstream and its impact downstream“Records in the Account Usage QUERY_HISTORY view do not always get recorded in the ACCESS_HISTORY view.”
↩︎ Exam trap 3“base_table in the base_objects_accessed column because that is the original source of the data in view_2.”
↩︎ Checkpoint - 7.
“A stored procedure or task can result in lineage between an upstream object and a downstream object.”
↩︎ Data lineage: tracing a bad value upstream and its impact downstream“This function returns a subset of the information provided by the Lineage tab in Snowsight.”
↩︎ Data lineage: tracing a bad value upstream and its impact downstream“Column lineage is not currently supported for semantic views.”
↩︎ Data lineage: tracing a bad value upstream and its impact downstream“Object dependencies, when an object references a base object but does not materialize or copy data, such as when a view references a table.”
↩︎ Checkpoint
Also cited
“You only specify the error notification integrations on a root task of a task graph.”
↩︎ Exam trap 2