Snowflake Bundle 2026_07 Is On by Default: What to Fix Before the Opt-Out Ends

Quick answer: Behavior change bundle 2026_07 became enabled by default in the Snowflake 10.37 release, dated 8 to 16 October 2026. You can still disable it until it becomes generally enabled. Snowflake plans that for a release after October 2026, and its deprecation note for the Cortex model allowlist says January 2027. The opt-out could end sooner, because the 10.37 release notes say bundle statuses change again at the next release with behaviour changes. Five of its 23 changes are rated high impact. They cover GRANT OWNERSHIP on owner-executed objects, the end of CORTEX_MODELS_ALLOWLIST, two internal row-timestamp columns, BITCOUNT, and METADATA$RANK in CORTEX_SEARCH_BATCH.

Last updated: October 2026

Snowflake switched bundle 2026_07 on in the 10.37 release, dated 8 to 16 October 2026, for every account where an administrator had not explicitly disabled it. Pipelines that have run normally since then may still be affected. Several of these changes only surface when one particular statement runs, such as an ownership transfer in a deployment script or a quarterly job that reads a column that can no longer be queried.


The bundle contains 23 changes. Snowflake rates five of them high impact, 15 medium and three low.


This follows our guide to bundle 2026_06. That bundle became generally enabled in the same 10.37 release and can no longer be switched off.


Where 2026_07 stands, and how long you can still opt out


StageRelease and datesWhat you can do
Disabled by default10.32, 5 to 9 September 2026Enable it on a test account
Enabled by default10.37, 8 to 16 October 2026Disable it to opt out for now
Generally enabledPlanned for a release after October 2026; the Cortex allowlist page says January 2027You can no longer disable it, because overrides are cleared and the changes become permanent

Disabling the bundle is a temporary measure. SYSTEM$DISABLE_BEHAVIOR_CHANGE_BUNDLE keeps working until the opt-out period ends. Snowflake doesn't reverse an explicit setting when a bundle becomes enabled by default. A disabled production account therefore stays disabled until general enablement clears the override. The bundle is all or nothing, and you can't keep one change and skip another.


That includes the Cortex change. Disabling 2026_07 restores the CORTEX_MODELS_ALLOWLIST fallback and stops model RBAC applying to embedding models. Roles then regain any model the allowlist still names, even on an account that revoked the all-models grant. Once your Cortex workloads pass with the bundle enabled, set the allowlist to 'None' so that the fallback grants nothing.


The opt-out may end before January 2027. Snowflake's 10.37 release notes say each bundle's status changes again in the following release with behaviour changes, and its policy guarantees a minimum of four weeks of opt-out. Bundle 2026_06 became generally enabled in 10.37, about five weeks after it was enabled by default in 10.32. We recommend finishing your fixes before Snowflake's next release with behaviour changes.


Check, disable or re-enable the bundle on the current account
-- ENABLED, DISABLED, or RELEASED once it is generally enabled.
SELECT SYSTEM$BEHAVIOR_CHANGE_BUNDLE_STATUS('2026_07');

-- Opt out while you fix something. Record who did it and why.
SELECT SYSTEM$DISABLE_BEHAVIOR_CHANGE_BUNDLE('2026_07');

-- Turn it back on once the fix is deployed.
SELECT SYSTEM$ENABLE_BEHAVIOR_CHANGE_BUNDLE('2026_07');

Snowflake's policy says account administrators make this change, and the documentation for SYSTEM$ENABLE_BEHAVIOR_CHANGE_BUNDLE says it can't be called from inside a stored procedure or a UDF. Each call applies to the current account only, which means production and non-production accounts need to be checked separately.


We need to correct our earlier article, which reported Snowflake's plan to enable 2026_06 by default in August 2026. The change took place in the 10.32 release, dated 5 to 9 September 2026. Because Snowflake's documentation marks its schedules as subject to change, we recommend checking SYSTEM$BEHAVIOR_CHANGE_BUNDLE_STATUS on each account instead of relying on a published date.


High impact: GRANT OWNERSHIP needs the target role in your session


Until this bundle, GRANT OWNERSHIP ON <object> TO ROLE <target_role> worked whether or not the target role was active in your session. For owner-executed objects it now succeeds only if the target role is active (it appears in CURRENT_AVAILABLE_ROLES) or the role running the statement has account-level MANAGE GRANTS. Owner-executed objects are those whose body or schedule runs with the owner's privileges. Snowflake's full list includes views, materialized views, dynamic tables, semantic views, external, directory and event tables, procedures, functions, data metric functions, tasks, alerts, pipes, eight policy types, Streamlit apps and Cortex Search services. Ordinary tables, schemas, databases, sequences and stages are not affected, and MANAGE GRANTS held on a database or schema does not count.


The error you will see (from Snowflake's documentation)
SQL compilation error: <object_domain> ownership can only be transferred to a role
that is activated in the current session or by a role with account-level MANAGE GRANTS.

Deployment pipelines are where this change is most likely to cause failures. A CI service user that creates a view and then hands ownership to a functional role it was never granted will now fail at that step. The same applies to schemachange or Terraform runs that transfer ownership of procedures and tasks at the end of a release.


There are two fixes. The narrower one is to grant the target role to the role the deployment runs as (GRANT ROLE <target_role> TO ROLE <deploy_role>), which places the target role in that role's hierarchy. A grant to the deploying user alone works only when the session has secondary roles activated. Either way, the deploying identity gains everything the target role can do, including reading its data. Check that role's grants before you add it.


The broader fix is to give the deployment role account-level MANAGE GRANTS, which also lets it change grants on everything else in the account. We recommend the first unless you already run a dedicated grants role. To find the statements that will be affected, run this query of our own, which lists recent ownership transfers.


Our own query: ownership transfers in the last 90 days
-- The /* bcr_2026_07_search */ tag stops this search listing itself.
SELECT /* bcr_2026_07_search */ start_time, user_name, role_name, query_text
FROM SNOWFLAKE.ACCOUNT_USAGE.QUERY_HISTORY
WHERE start_time >= DATEADD('day', -90, CURRENT_TIMESTAMP())
  AND query_text ILIKE '%grant ownership%'
  AND query_text NOT ILIKE '%bcr_2026_07_search%'
ORDER BY start_time DESC;

-- Then check the ones that target owner-executed objects (views,
-- dynamic tables, materialized views, procedures, functions, tasks,
-- alerts, pipes, policies, Streamlit apps, Cortex Search services),
-- and whether role_name holds the target role.

High impact: CORTEX_MODELS_ALLOWLIST no longer controls model access


Before this bundle, Snowflake checked model RBAC first and fell back to the CORTEX_MODELS_ALLOWLIST account parameter, and RBAC wasn't enforced for embedding models at all. With 2026_07 enabled, the allowlist is not consulted, and RBAC also covers AI_EMBED, AI_MULTI_EMBED, AI_SIMILARITY, EMBED_TEXT_768 and EMBED_TEXT_1024. Snowflake's allowlist deprecation page adds that the enforcement also covers Cortex Search. Include your search services and any CORTEX_SEARCH_BATCH jobs when you test model access.



The migration is described as best effort, and Snowflake warns it may not cover every execution context. Three cases need attention. Native App code uses the app's own role hierarchy instead of the consumer account's PUBLIC role. Grant the model application role to the application or to the role used inside it. Restricted caller's rights procedures don't evaluate caller grants for model RBAC, and a grant to PUBLIC is enough there. Managed reader accounts without the SNOWFLAKE.MODELS schema keep using the allowlist during the migration.


ACCOUNTADMIN always has access to every model. A test run under that role, or with secondary roles active, can therefore pass even when the workload's own role lacks the grants it needs. Run each AI workload as the role it normally runs under, with secondary roles switched off. If a test fails, check the base privileges as well. The role still needs USE AI FUNCTIONS (or the per-function USE AI FUNCTION privilege) and one of the CORTEX_USER or AI_FUNCTIONS_USER database roles.


An unrelated change came into effect in the same week. Under Snowflake's August 2026 model deprecations, claude-4-sonnet reached end of life on 14 October 2026. If an AI_COMPLETE call started failing in mid-October, check the model name with SHOW CORTEX BASE MODELS before you change grants.


Check what the migration left behind (adapted from Snowflake's documentation; the comments and grouping are ours)
SHOW PARAMETERS LIKE 'CORTEX_MODELS_ALLOWLIST' IN ACCOUNT;
SHOW GRANTS TO ROLE PUBLIC;
SHOW GRANTS TO APPLICATION ROLE SNOWFLAKE.PUBLIC;

-- List the per-model application roles you can grant.
SHOW APPLICATION ROLES LIKE 'CORTEX-MODEL%' IN APPLICATION SNOWFLAKE;

-- Test as the real role, without secondary roles widening access.
USE SECONDARY ROLES NONE;

If you want to stop every user reaching every model, revoking from PUBLIC is not enough. In accounts whose allowlist was 'All', which includes new accounts, the all-models grant sits on the SNOWFLAKE.PUBLIC application role, and Snowflake's documentation says a plain REVOKE does not remove it and does not persist across upgrades. Before you run the procedure below as ACCOUNTADMIN, grant specific model roles to the roles that need them, or their users will lose access. Model role names are case-sensitive quoted identifiers, with the model name in upper case, as in Snowflake's example.


Grant a specific model role (from Snowflake's documentation)
GRANT APPLICATION ROLE SNOWFLAKE."CORTEX-MODEL-ROLE-LLAMA3.1-70B" TO ROLE MY_ROLE;

Remove the bootstrap all-models grant, then the call that restores it (from Snowflake's documentation)
CALL SNOWFLAKE.LOCAL.REVOKE_FROM_PUBLIC_APPLICATION_ROLE(
  'APP_ROLE',
  'CORTEX-MODEL-ROLE-ALL'
);

CALL SNOWFLAKE.LOCAL.GRANT_TO_PUBLIC_APPLICATION_ROLE(
  'APP_ROLE',
  'CORTEX-MODEL-ROLE-ALL'
);

Afterwards, re-run SHOW GRANTS TO APPLICATION ROLE SNOWFLAKE.PUBLIC to confirm the grant is gone. Grants to the account-level PUBLIC role that you manage yourself are removed with an ordinary REVOKE APPLICATION ROLE. Retest any restricted caller's rights procedure that calls Cortex, because those procedures depend on grants to PUBLIC. Our guide to agent and MCP permissions covers role design for agents.


High impact: three changes that make working SQL fail or return different results


Internal row-timestamp columns are blocked. Queries could reference METADATA$PERSISTED_ROW_MODIFIED_TIMESTAMP and METADATA$FILE_TXN_END_TIME, even though neither was ever documented. Any SQL that names them now fails with an invalid identifier error, including statements inside procedures, tasks, dynamic tables and SQL generated by frameworks. Code that uses them may not be known to the current team. We recommend searching for both names before assuming they are unused.


The supported column, METADATA$ROW_LAST_COMMIT_TIME, is unchanged. Tables expose it once row timestamps are enabled (ROW_TIMESTAMP = TRUE). Rows created before row timestamps were enabled return NULL, which means an incremental filter such as > :high_watermark will skip them. Before switching a job over, decide how the job treats rows with a NULL timestamp.


BITCOUNT gets a defined return type and sign handling. The function has existed since 2020 but was not documented until now. Snowflake has now pinned down two of its behaviours. The return type is now always BIGINT instead of following the argument's width, and negative integers are sign-extended to 128 bits before bits are counted. In Snowflake's own example, BITCOUNT(-1::NUMBER(2,0)) returned 8 and now returns 128. If you count flags in bitmask columns that can hold negative values, the totals change without any error.


METADATA$RANK is gone from CORTEX_SEARCH_BATCH. Queries that reference it now fail at compile time with "referencing METADATA$RANK is not supported". Results still come back in ranked order, and Snowflake's documented replacement uses ROW_NUMBER() to rank each row within its request. If you followed our batch Cortex Search guide, check any downstream SQL that filtered on rank.


Replacement for METADATA$RANK (from Snowflake's documentation)
SELECT
    q.query_text,
    r.*,
    ROW_NUMBER() OVER (
        PARTITION BY r.METADATA$REQUEST_ID
        ORDER BY SEQ8()
    ) AS row_rank
FROM my_queries AS q,
LATERAL CORTEX_SEARCH_BATCH(
    service_name => 'my_db.my_schema.my_service',
    query        => q.query_text,
    limit        => 10
) AS r;

The search below is our own. It covers this section and the invoker_identity change further down, in both recent statements and object definitions. For each BITCOUNT hit, check whether the argument can be negative. Dynamic table and task definitions are not in these views. Check the SHOW DYNAMIC TABLES and SHOW TASKS output as well.


Our own search for identifiers this bundle blocks, removes or changes
-- Statements run in the last 90 days. The /* bcr_2026_07_search */
-- tag stops the search listing itself on later runs.
SELECT /* bcr_2026_07_search */ start_time, user_name,
       LEFT(query_text, 200) AS query_start
FROM SNOWFLAKE.ACCOUNT_USAGE.QUERY_HISTORY
WHERE start_time >= DATEADD('day', -90, CURRENT_TIMESTAMP())
  AND query_text NOT ILIKE '%bcr_2026_07_search%'
  AND query_text ILIKE ANY ('%METADATA$PERSISTED_ROW_MODIFIED_TIMESTAMP%',
                            '%METADATA$FILE_TXN_END_TIME%',
                            '%METADATA$RANK%',
                            '%invoker_identity%',
                            '%BITCOUNT(%')
ORDER BY start_time DESC;

-- Views, procedures and UDFs whose definitions name the same identifiers.
SELECT /* bcr_2026_07_search */ 'VIEW' AS object_type,
       table_catalog AS db, table_schema AS sch, table_name AS name
FROM SNOWFLAKE.ACCOUNT_USAGE.VIEWS
WHERE deleted IS NULL
  AND view_definition ILIKE ANY ('%METADATA$PERSISTED_ROW_MODIFIED_TIMESTAMP%',
      '%METADATA$FILE_TXN_END_TIME%', '%METADATA$RANK%',
      '%invoker_identity%', '%BITCOUNT(%')
UNION ALL
SELECT 'PROCEDURE', procedure_catalog, procedure_schema, procedure_name
FROM SNOWFLAKE.ACCOUNT_USAGE.PROCEDURES
WHERE deleted IS NULL
  AND procedure_definition ILIKE ANY ('%METADATA$PERSISTED_ROW_MODIFIED_TIMESTAMP%',
      '%METADATA$FILE_TXN_END_TIME%', '%METADATA$RANK%',
      '%invoker_identity%', '%BITCOUNT(%')
UNION ALL
SELECT 'FUNCTION', function_catalog, function_schema, function_name
FROM SNOWFLAKE.ACCOUNT_USAGE.FUNCTIONS
WHERE deleted IS NULL
  AND function_definition ILIKE ANY ('%METADATA$PERSISTED_ROW_MODIFIED_TIMESTAMP%',
      '%METADATA$FILE_TXN_END_TIME%', '%METADATA$RANK%',
      '%invoker_identity%', '%BITCOUNT(%');

Medium impact, grouped by what they break


Fifteen changes are rated medium. About a third of them raise a new error that you will notice. Roughly half change a value, a type, a row count or a privilege without any error, and those need the closest review.


ChangeWhat it breaksWhat to do
AI_EMBED and AI_SIMILARITY return NULL when a row failsBatch jobs that relied on an error to stop now finish with NULL vectors or scoresAdd NULL checks, or pass the new return_error_details argument to get the error per row
BOOLEAN to NUMBER casts take the target typeCTAS column types and schema checks that expected NUMBER(2,0); CAST(TRUE AS NUMBER(1,1)) now errorsReview casts in CTAS and type-dependent pipelines
New string columns from CTAS, materialized views and dynamic tables get a recomputed byte lengthTools that read the column's byte length from SHOW COLUMNSCast to an explicit VARCHAR length where it matters
Arrays cast to VECTOR now error on overflowINT values outside INT32 and FLOAT values beyond float32, which used to truncate or become infinityCheck element ranges before casting
ACCESS_HISTORY drops invoker_identityAudit dashboards and scripts that select that columnRead agents_info, an array ordered from the nearest agent to the top-level agent and NULL when no agent is involved, and rewrite queries that expected one object per row
Expired key-pair JWTs return error 390318Alerting that matched 390303 to detect expiryMatch both codes until general enablement, because accounts with the bundle disabled still return 390303
Sessions close when their security integration is disabled or droppedLong-running OAuth, SAML or OIDC sessions whose integration is later disabled or droppedExpect re-authentication on the session's next request
DESCRIBE needs explicit accessRoles that described objects through MANAGE GRANTS or APPLY TAG ON ACCOUNT aloneGrant the least privilege that allows it, such as REFERENCES on tables and views or USAGE on functions, without transferring ownership
Future grants on data metric functions and functions are separateFuture grants that covered both types by accidentCheck SHOW FUTURE GRANTS in schemas and databases, add a future grant for the intended type, and grant directly on objects created since the bundle was enabled
Semantic views reject FACTS with DIMENSIONSQueries that ran but returned arbitrary valuesRewrite as dimensions only, or facts only (see below)
SESSIONS reports authentication_method as 'None' for user task sessionsFilters on IS NULLFilter on 'None', or both during the transition
SHOW DATABASES lists mountless databases from organisation listingsScripts that assume every row is a local databaseAccounts without organisation listings see no change
ALTER ICEBERG TABLE ... CONVERT TO MANAGED keeps the original pathConversions that overlap an existing managed table's path now failSet BASE_LOCATION explicitly if you want a new path
Notebook services can't be resumed with ALTER SERVICEScripts that resume notebook services in SQLManage them in Snowsight
MONITOR now grants access to Cortex Search refresh historyNo existing access is removedReview who holds MONITOR on search services

We would check the AI_EMBED change first. A job that used to stop with an error on a bad row will now complete successfully, and the NULL rows show up later in similarity searches. With Snowflake's default NULL ordering, ORDER BY score DESC puts NULL scores first. A top-k query can then return the failed rows as its best matches. Filter on score IS NOT NULL or add NULLS LAST.


For the semantic view change, Snowflake publishes a detection query and two rewrites. The first rewrite returns unique rows and the second keeps duplicates. Our comparison of semantic views and the dbt Semantic Layer covers how these views are built.


Find semantic view queries that mix FACTS and DIMENSIONS (from Snowflake's documentation)
SELECT *
FROM SNOWFLAKE.ACCOUNT_USAGE.QUERY_HISTORY
WHERE start_time >= DATEADD('day', -30, CURRENT_TIMESTAMP())
  AND RLIKE(query_text,
    $$.*from\s+semantic_view.*(facts.*dimensions|dimensions.*facts).*$$, 'is')
ORDER BY start_time DESC;

Rewrite that returns unique rows (from Snowflake's documentation)
SELECT *
FROM SEMANTIC_VIEW(
  sv
  DIMENSIONS f1, d1
);

-- Alternatively, using direct semantic view syntax:
SELECT f1, d1
FROM sv
GROUP BY f1, d1;

Rewrite that keeps duplicate rows (from Snowflake's documentation)
SELECT *
FROM SEMANTIC_VIEW(
  sv
  FACTS f1, d1
);

-- Alternatively, using direct semantic view syntax:
SELECT f1, d1
FROM sv;

Three changes are rated low impact. Cloning a database no longer copies its EVENT_TABLE parameter, and a user with the ACCOUNTADMIN role must set it on the clone. The STAGE_TYPE column in the STAGES views now returns 'Internal Named' instead of NULL for internal stages with SNOWFLAKE_SSE encryption. Information Schema views now honour MANAGE GRANTS, caller grants and inherited grants, and some roles will now see more rows than before.


A test plan for an account where the bundle is already on


For 2026_07 the testing period ended with the 10.37 release. Unlike our 2026_06 plan, this one assumes the bundle is already enabled on your accounts.



Our own query: statements that failed with errors documented for this bundle
SELECT start_time, user_name, role_name, error_message,
       LEFT(query_text, 200) AS query_start
FROM SNOWFLAKE.ACCOUNT_USAGE.QUERY_HISTORY
WHERE start_time >= '2026-10-08'
  AND (error_message ILIKE '%ownership can only be transferred to a role%'
       OR error_message ILIKE '%METADATA$RANK is not supported%'
       OR error_message ILIKE '%Querying FACTS with DIMENSIONS%'
       OR error_message ILIKE '%elements that overflow%'
       OR (error_message ILIKE '%invalid identifier%'
           AND (query_text ILIKE '%METADATA$PERSISTED_ROW_MODIFIED_TIMESTAMP%'
                OR query_text ILIKE '%METADATA$FILE_TXN_END_TIME%'
                OR query_text ILIKE '%invoker_identity%')))
ORDER BY start_time DESC;

Bundle 2026_08 is already in its testing period. It includes CREATE OR REPLACE copying grants by default and user grants applying regardless of secondary roles, both rated high impact. We recommend enabling it on a test account now. If that account holds real users, first run ALTER ACCOUNT SET INCLUDE_PROTECTED_USER_DATA = FALSE. The bundle's ALL_USER_DETAILS change, also rated high, lets every session read the names and email addresses of active users.


Pranay Vatsal, Founder & CEO

Pranay Vatsal is the Founder & CEO of CelestInfo with deep expertise in Snowflake, data architecture, and building production-grade data systems for global enterprises.

Related Articles

Frequently Asked Questions

Q: When does Snowflake bundle 2026_07 become generally enabled?

Snowflake's bundle page plans general enablement for a release after October 2026, and its Cortex allowlist page says January 2027, both subject to change. The opt-out could end sooner, because the 10.37 release notes say bundle statuses change again at the next release with behaviour changes.

Q: Can I still disable bundle 2026_07?

Yes, until it becomes generally enabled. Run SELECT SYSTEM$DISABLE_BEHAVIOR_CHANGE_BUNDLE('2026_07') on the account. An explicit setting stays in place until general enablement, which clears it and makes every change permanent. You can't disable individual changes, and disabling the bundle also restores the CORTEX_MODELS_ALLOWLIST fallback.

Q: Which changes in bundle 2026_07 are high impact?

Five changes are rated high impact: GRANT OWNERSHIP on owner-executed objects now needs the target role active in the session or MANAGE GRANTS; CORTEX_MODELS_ALLOWLIST no longer controls model access; METADATA$PERSISTED_ROW_MODIFIED_TIMESTAMP and METADATA$FILE_TXN_END_TIME are blocked; BITCOUNT returns BIGINT and sign-extends negative values to 128 bits; and METADATA$RANK is removed from CORTEX_SEARCH_BATCH.

Q: What replaces CORTEX_MODELS_ALLOWLIST?

Model RBAC replaces it. Each Cortex model has an application role in the SNOWFLAKE application, named CORTEX-MODEL-ROLE- followed by the model name in upper case, used as a quoted identifier, and CORTEX-MODEL-ROLE-ALL covers every model. A plain REVOKE does not remove the all-models grant on SNOWFLAKE.PUBLIC, and Snowflake documents the SNOWFLAKE.LOCAL.REVOKE_FROM_PUBLIC_APPLICATION_ROLE procedure for that.

Q: Why does my deployment fail with 'ownership can only be transferred to a role that is activated in the current session'?

That error comes from bundle 2026_07. For owner-executed objects such as views, dynamic tables, procedures, functions, tasks and policies, GRANT OWNERSHIP now requires the target role to be active in your session or the executing role to hold account-level MANAGE GRANTS. Granting the target role to the role the deployment runs as is the narrower fix.

Q: Does bundle 2026_07 affect drivers, connectors or Snowpark?

None of the 23 change pages mentions a driver, connector, client version or Snowpark. Two changes still affect clients: an expired key-pair JWT now returns error 390318 instead of 390303, and sessions close on their next request when the OAuth, SAML or OIDC integration behind them is disabled or dropped.