Troubleshoot dynamic table refresh issues¶
This page helps you diagnose and resolve dynamic table refresh problems. For creation-time issues, see Troubleshoot dynamic table creation issues. For permission-related failures, see Troubleshoot dynamic table permission issues.
Start by running the quick health check below. If your symptom is not visible there, scan the section headings to find a match. For slow refresh diagnostics, see Optimize queries for incremental refresh.
You can also view refresh status in the Refresh History tab in Snowsight.
Look for rows where scheduling_state is not RUNNING or where actual_lag_minutes greatly
exceeds your target lag. If this query returns no rows, see
Troubleshoot permission issues
to check your role’s privileges.
If you encounter an issue not listed here, contact Snowflake Support.
Refresh fails with UPSTREAM_ FAILED status¶
When a dynamic table depends on another dynamic table that failed to refresh, the downstream table reports UPSTREAM_FAILED. The root cause is always upstream.
-
Find which dynamic tables show UPSTREAM_FAILED:
-
Read the
state_messagecolumn, which names the failing upstream table directly. In this example,dt_ordershas aUSER_ERROR, which means its own definition has a problem. That failure cascades todt_orders_daily. -
Alternatively, open the Graph view in Snowsight to visualize the pipeline. Navigate to Transformation > Dynamic tables, select any table in the pipeline, and switch to the Graph tab. The failing upstream table is highlighted.
-
Fix the root-cause table first. After the upstream table refreshes successfully, the downstream UPSTREAM_FAILED tables recover automatically on their next scheduled refresh.
Dynamic table is suspended¶
A suspended dynamic table stops refreshing entirely. No new refreshes are attempted until you resume it.
-
Check the scheduling state and suspension reason:
-
Determine why it was suspended. Query the scheduling state to see the reason code:
The most common causes are manual suspension (
USER_SUSPENDED), five consecutive scheduled refresh failures (SUSPENDED_DUE_TO_ERRORS), and cascade from a suspended upstream table (UPSTREAM_USER_SUSPENDEDorUPSTREAM_SUSPENDED_DUE_TO_ERRORS).For the complete list of suspension reason codes and resume cascade behavior, see Manage dynamic tables.
-
Fix the root cause (for example, correct the column name in the dynamic table’s definition), then resume:
When you resume a dynamic table, downstream tables that were suspended as a cascade effect (reason
UPSTREAM_USER_SUSPENDEDorUPSTREAM_SUSPENDED_DUE_TO_ERRORS) also resume automatically. Tables you manually suspended must be resumed individually. Resuming restores schedulability but does not trigger an immediate refresh.
Refresh fails with an error¶
For a complete list of refresh error codes with causes and resolutions, see Error code reference for dynamic tables. You can search that page by error message or error code.
If the error message includes a query_id, open the query profile in Snowsight to see resource usage and identify bottlenecks. See Exploring execution times.
Refresh fails after a schema change on a base table¶
When a column referenced by the dynamic table’s definition is dropped or renamed in a base table,
refreshes fail. The dynamic table can’t adapt to the schema change automatically unless it uses SELECT * with schema evolution (see Evolve dynamic table pipelines).
-
Check recent refresh failures for schema-related errors:
-
Identify the schema change. Compare the dynamic table’s definition against the current base table schema:
Look for column names in the GET_DDL output that don’t appear in the DESCRIBE output.
-
Resolve the mismatch. Either restore the dropped column on the base table or recreate the dynamic table with an updated definition that references the correct columns.
Tip
If your dynamic table uses explicit column lists and a base table schema change causes a refresh failure,
consider switching to SELECT * or SELECT * EXCLUDE (...) for automatic schema evolution. See
Evolve dynamic table pipelines for details.
dbt or CREATE OR REPLACE breaks change tracking¶
When a base table is replaced with CREATE OR REPLACE, the new table is a different object.
The dynamic table loses its reference to the original table’s change tracking history, causing
incremental refresh to fail.
-
Check refresh history for change-tracking errors:
The specific error depends on what changed. If only change tracking was lost (same schema), you see:
If the schema also changed:
-
If you use dbt or other tools that run
CREATE OR REPLACE TABLE, use one of these workarounds:Option A: Suspend and resume around DDL changes
Suspending prevents failures during the DDL window. The dynamic table still reinitializes after resume, but you avoid transient failures and control the timing.
Option B: Re-enable change tracking after replacement
If your tooling must use
CREATE OR REPLACE, add a post-hook to re-enable change tracking:Alternatively, include
CHANGE_TRACKING = TRUEdirectly in theCREATE OR REPLACE TABLEstatement.Option C: Use
INSERT OVERWRITEinstead ofCREATE OR REPLACEINSERT OVERWRITEpreserves the table object and its change tracking history: -
After applying the workaround, resume the dynamic table if it was suspended:
Dynamic table reinitializes unexpectedly¶
Reinitialization forces Snowflake to reprocess the entire dynamic table from scratch, even if it normally uses incremental refresh. This is more expensive than a regular refresh and produces a large change set for streams that depend on the dynamic table. Streams on the dynamic table survive reinitialization but their next read returns the entire table as changes. Recreate the stream if you want to reset the offset and avoid processing this large change set. See Streams on a dynamic table return a large change set after reinitialization.
-
Confirm that a reinitialization happened by checking the
refresh_actioncolumn: -
Identify the trigger. The most common causes are
CREATE OR REPLACEon the dynamic table itself (appears asrefresh_trigger = CREATIONin refresh history) or on an upstream base table, and schema changes (dropping or renaming a column) on a base table that the dynamic table references.For the complete list of reinitialization triggers, see Evolve dynamic table pipelines.
-
To control when reinitialization happens and avoid refresh failures during DDL changes (such as dbt runs), suspend the dynamic table before the DDL and resume it after. The dynamic table still reinitializes on its initial refresh after resume, but you avoid transient failures and control the timing:
For more information about reinitialization, see Reinitialization triggers.
Streams on a dynamic table return a large change set after reinitialization¶
When a dynamic table reinitializes, all of its data is reprocessed. After a reinitialization, the stream exposes all row-level differences between its last-read offset and the reinitialized output. Every row in the new output appears as an INSERT, and every row from the previous version appears as a DELETE. This can produce a very large change set. For more details, see Use streams on dynamic tables.
-
Confirm that the dynamic table reinitialized recently:
-
Recreate the stream to reset the offset to the current state of the dynamic table:
-
To prevent recurrence, minimize reinitializations. See Dynamic table reinitializes unexpectedly.
-
To reduce the volume of changes that downstream consumers must process after a reinitialization, add a RELY primary key to the dynamic table. Snowflake merges matching INSERT/DELETE pairs into UPDATEs for downstream dynamic tables and streams.
For more information about streams on dynamic tables, see Use streams on dynamic tables.
Dynamic table refreshes as FULL when you expected INCREMENTAL¶
If a dynamic table was created with REFRESH_MODE = AUTO, the resolved mode is permanent and
can’t be changed with ALTER. See Dynamic table refresh modes for details on
how AUTO resolves and how to verify the resolved mode.
If you need incremental refresh, fix the definition and recreate the dynamic table with
CREATE OR REPLACE DYNAMIC TABLE ... REFRESH_MODE = INCREMENTAL to force validation at
creation time.
Row access policies or masking policies can block incremental refresh¶
Row access and masking policies on base tables can block incremental refresh depending on which functions they use. For supported combinations, see Supported queries for dynamic tables.
Typical error messages:
-
Identify which base tables have row access or masking policies:
-
Resolution options:
Option A: Switch to FULL refresh mode. Full refresh evaluates the entire query from scratch on each refresh, so context functions in policies work correctly:
Option B: Apply the policy on the dynamic table instead. Remove the policy from the base table and apply it to the dynamic table. Since the policy runs at query time (not refresh time), context functions work correctly:
IS_ ROLE_ IN_ SESSION() only accepts constant arguments in incremental mode¶
When a dynamic table uses incremental refresh and the definition references a base table with a
row access policy that calls IS_ROLE_IN_SESSION(), the policy function must use only constant
string arguments. Variable or column-based arguments are not supported in incremental mode.
-
Check the row access policy definition to see how
IS_ROLE_IN_SESSION()is called: -
If the policy uses a column reference as the argument (for example,
IS_ROLE_IN_SESSION(allowed_role)), this is not supported in incremental mode. -
Resolution options:
- Rewrite the policy to use constant role names:
IS_ROLE_IN_SESSION('ANALYST_ROLE'). - Move the policy from the base table to the dynamic table, where it runs at query time rather than refresh time.
- Switch the dynamic table to
REFRESH_MODE = FULL.
- Rewrite the policy to use constant role names:
Projection policies cause unexpected refresh behavior¶
Projection policies on base table columns can affect dynamic table refresh behavior. If a projection policy restricts a column the definition references, the refresh either sees masked data (producing incorrect output) or fails outright if the owner role is not in the policy’s allowed list.
-
Check if any base tables have projection policies:
-
If the dynamic table’s owner role is not in the projection policy’s allowed list, the refresh sees masked or restricted data. Grant the owner role the appropriate access or modify the projection policy:
-
If you want the dynamic table to contain the unmasked data (for downstream consumption with separate access controls), ensure the owner role has full access through the projection policy.
Dynamic table is not refreshing after RESUME¶
After you run ALTER DYNAMIC TABLE ... RESUME, a refresh may not be triggered
immediately. If the dynamic table exceeds its target lag, investigate the following.
-
Confirm the scheduling state changed to RUNNING:
-
Incremental refresh relies on time-travel data. If the dynamic table was suspended longer than the DATA_RETENTION_TIME_IN_DAYS setting (default: 1 day for Standard Edition, configurable up to 90 days for Enterprise Edition and higher), inherited from the database or schema unless set explicitly, this data has expired and incremental refresh can’t find the historical change data. The refresh fails with:
In this case, you must recreate the dynamic table. Use
SELECT GET_DDL('DYNAMIC_TABLE', 'mydb.myschema.dt_orders')to capture the existing definition before recreation. Downstream dynamic tables will also reinitialize after the recreation. To recreate a dynamic table without reprocessing historical data, see Seed a dynamic table with BACKFILL FROM. -
If the scheduling state shows RUNNING but no refreshes appear in the history, trigger a manual refresh to confirm the dynamic table can refresh:
If the warehouse was dropped or reassigned during suspension, see the warehouse error in Refresh fails with an error.
Scheduled refreshes are being skipped¶
A skipped refresh means Snowflake chose not to run a scheduled refresh. The dynamic table’s data doesn’t advance, but no error is reported.
-
Check for skipped refreshes in the refresh history:
-
Interpret the
state_code:State code Meaning Resolution UPSTREAM_FAILED An upstream dynamic table failed or was skipped Fix the upstream table first NOT_EFFECTIVE_TICK_TO_REFRESH Snowflake determined this scheduled refresh attempt was not effective (refresh duration greatly exceeds target lag) Increase the warehouse size, optimize the definition, or increase target lag SKIPPED with
UPSTREAM_FAILEDmeans a single refresh attempt is skipped because an upstream table failed this cycle. SUSPENDED means the table stopped refreshing entirely after repeated failures (five consecutive failures by default).If a previous refresh is still running when the next scheduled refresh attempt arrives, the new scheduled refresh attempt is skipped and the current refresh is allowed to complete. To reduce skips from overlapping refreshes, increase the warehouse size or increase the target lag.
-
If you see many consecutive skips with NOT_EFFECTIVE_TICK_TO_REFRESH, Snowflake is adjusting because refreshes take much longer than the target lag. For example, a dynamic table with a 1-minute target lag but 1-hour refresh duration causes most scheduled refresh attempts to be skipped.
To resolve this, either increase the target lag to a realistic value or improve refresh performance. See Optimize queries for incremental refresh.
Note
Manual refreshes (ALTER DYNAMIC TABLE ... REFRESH) are never skipped, but frequent manual
refreshes on a dynamic table with downstream consumers can prevent those downstream dynamic tables
from refreshing on schedule.
Refreshes show cost but produce no new rows¶
A zero-row refresh still consumes compute if Snowflake detects upstream changes and resumes the warehouse to evaluate them.
-
Check whether recent refreshes consumed warehouse resources:
-
Understand the two types of zero-row refreshes:
Type Warehouse used Cost Explanation NO_DATA No None No changes detected in upstream objects. The warehouse stays suspended. Zero-row SUCCEEDED Yes Compute credits consumed Changes were detected upstream, so the warehouse resumed to evaluate them, but the net result was zero rows applied to the dynamic table. -
If zero-row refreshes happen frequently and the cost is a concern, check whether upstream processes are generating changes that don’t affect the dynamic table’s output (for example, updating columns not referenced in the definition).
For more information, see Understanding costs for dynamic tables.
What’s next¶
-
To troubleshoot creation-time issues, see Troubleshoot dynamic table creation issues.
-
To troubleshoot permission-related failures, see Troubleshoot dynamic table permission issues.
-
To investigate slow refreshes or optimize refresh performance, see Optimize queries for incremental refresh.
-
To set up proactive monitoring and alerts for dynamic table refresh failures, see Monitor dynamic tables.
-
To understand the difference between INCREMENTAL, FULL, and AUTO refresh modes, see Dynamic table refresh modes.
-
To query an event table for dynamic table failures across a database:
For more information about setting up event tables for dynamic table monitoring, see Monitor dynamic tables.
-
If you encounter an issue not covered here, contact Snowflake Support.