Skip to content

Release Notes

2026.8.23-6e405e5

Native App


Version 2026.8.23-6e405e5 of the RelationalAI Native App is now available!

Note that RelationalAI Native App upgrades are applied automatically and require no action on your part, unless you have opted-in to manual upgrades.

Bug Fixes

  • Loading a Snowflake-managed Iceberg table now stops with a clear error when a column's data type doesn't match the table's declared data type, instead of silently returning incomplete results. Update the column's declared data type to match the source.

  • Fixed an issue that could prevent changes to a Snowflake-managed Iceberg table from being picked up, so your queries could keep returning data from an earlier version of the table.

1.28.0

Python SDK


Version 1.28.0 of the relationalai Python package is now available!

To upgrade, activate your virtual environment and run the following command:

pip install --upgrade relationalai

New Features and Enhancements

  • PyRel now records your model's change history automatically every time you deploy to Snowflake with rai models deploy. This history is called the op log, and it's what makes rai models branch, pull, and merge work, so those commands now work right away with no setup. To turn recording off, set oplog.enabled: false in raiconfig.yaml.

  • When you deploy a model, a concept and its subconcepts (declared with extends=) can now be built by different reasoners at the same time. For example, one subconcept can load straight from a Snowflake table while another is derived by rules. Querying the parent concept returns rows from all of its subconcepts together. Previously, every subconcept had to use the same reasoner.

  • Instead of writing separate SQL queries to explore a Snowflake database table by table, you can now run rai explore schema to capture its full structure (column types, primary and foreign key candidates, and value distributions) as a single JSON file. This helps when you're building a semantic model from an existing database and want to understand it first. It supports Snowflake sources only for now.

    For example:

    rai explore schema --database DEMO_TELCO --schema RAW --out schema.json
    
  • You can now define more than one decision problem on the same model, each as its own Problem. Once a model has more than one, give each Problem a unique name using the name parameter so PyRel can tell them apart, and match each one to the same problem every time you redeploy.

  • You can now use aggregates.string_join in models deployed to Snowflake. Use index= to control the order the values are joined in, or leave it out to join them in ascending order by value.

Bug Fixes

  • If your deployed model's target schema also holds tables or views you didn't create with PyRel, tearing down the model no longer removes them. rai models teardown now deletes only the objects RelationalAI created, and never drops the schema itself, even with --force. If RelationalAI created the schema, teardown reports it separately, along with the SQL needed to remove it.

  • Deploying a model no longer crashes with ExtractionError: Property owner must be user schema object when it adds a property to a built-in concept. This came up in many common models, such as any model that uses the graph or prescriptive reasoner, or that simply calls Error.new(message=...). If you set oplog.enabled: false only to work around this crash, you can now remove that setting.

  • In a deployed model, grouped aggregate queries now return correct results when a grouped aggregate (using .per()) shares a variable with another aggregate or lookup in the same rule. Some of these queries previously returned wrong rows, too few rows, or were rejected. Only deployed models were affected.

  • In a deployed model, an aggregate combined with a fallback value using | (for example, count(C).per(C.grp) | 0) now returns one correct row per group. Before, it could return wrong rows, or the deploy could fail on Snowflake with Unsupported subquery type cannot be evaluated. Only deployed models were affected.

  • A query that uses union() to express an OR condition across differently filtered joins no longer fails to deploy to Snowflake with Unsupported subquery type cannot be evaluated.

  • In a deployed model, a concept with a property derived from another of its own properties no longer fails to deploy when nothing else in the model creates that concept. It now deploys with zero rows, which matches the fact that nothing populates it.

  • A model no longer fails to deploy to Snowflake with an error like invalid identifier '__VAR_N' when a filtered, grouped aggregate is used to classify an existing entity, such as model.where(R(x), c := per(x).count(y), c > 1).define(Flag(x)).

  • A model with a concept that uses implicit identity no longer silently drops rows when the same data is read more than once during deploy. No model changes are needed. Redeploying applies the fix.

  • Compiling a model with a large union(), such as hundreds of filter fragments feeding one rule, is now much faster. A compile that used to take over a minute now finishes in a few seconds.

  • If your deployment role can't change Snowflake log or trace levels, deploying no longer shows a false Deploy Step Skipped warning when your role already inherits a sufficient level from the account, database, or schema. The warning still appears when the level really is too low, which you can fix by granting your role the MODIFY LOG LEVEL and MODIFY TRACE LEVEL privileges.

1.27.1

Python SDK


Version 1.27.1 of the relationalai Python package is now available!

To upgrade, activate your virtual environment and run the following command:

pip install --upgrade relationalai

New Features and Enhancements

  • Running a query or deploying a model that uses an undirected graph is now faster. PyRel builds the graph as part of that work, and before this release that build slowed down sharply as the number of edges grew. In one case, an undirected Graph with 200,000 edges took about 41 seconds to build. That same graph now takes about 1 second.

Dependency Updates

  • PyRel now requires DuckDB 1.5.0 or newer. DuckDB is installed automatically with PyRel, so most users don't need to do anything. If you have pinned DuckDB to an older 1.4.x version, allow 1.5.0 or newer before you install or upgrade PyRel.

1.27.0

Python SDK


Version 1.27.0 of the relationalai Python package is now available!

To upgrade, activate your virtual environment and run the following command:

pip install --upgrade relationalai

New Features and Enhancements

  • When a concept or relationship is built directly from your source Snowflake tables — without any additional computation in PyRel — model deployment now creates it as a SQL view instead of a table, which avoids unnecessary storage and refresh work. If you need it stored as a table, set type: table for that output under deployment.outputs.overrides. See Choose how outputs are materialized for details.

  • Redeploying a model now keeps existing deployed tables' data and Snowflake grants where possible, instead of dropping and recreating the tables. Views and dynamic tables are still recreated, but their grants are now preserved too. Some changes, such as changing an output column's type, can still require recreating a table.

  • Model deployment now tags each schema it creates as RAI-managed, which supports safer cleanup later. If your deployment role can't apply that tag, deployment now stops with a clear error telling you to grant APPLY on the tag (or APPLY TAG on the account) instead of leaving an untagged schema behind.

  • Temporary tables created by PyRel when deploying a model now live in the deployment's _META schema instead of appearing next to your model outputs, keeping the target schema limited to your model's objects.

Bug Fixes

  • common.hash() now produces different values than in earlier releases. This matters mainly when a hash is saved rather than computed on the fly — for example, when a deployed model materializes a property or relationship whose value comes from a hash, or when you export query results that include a hash to a table. Before upgrading, search your model code for common.hash( and plan to recompute any stored hashes that must stay stable.

  • In a deployed model, common.parse_uuid() now works consistently. A UUID that you parse and then compare against an entity in your model now matches instead of silently returning no rows, and common.uuid_to_string() applied to a parsed UUID now returns a plain 32-character value instead of dashed UUID text. Pass UUIDs in the standard dashed form, and update anything that expected the dashed output.

  • A query that uses one select() inside another expression now returns the correct rows. Previously, a nested selection could drop rows or ignore its own filter.

  • Selecting a constant value in a query no longer fails with a GROUP BY term out of range error when combined with other properties and relationships, and now returns the expected rows.

  • Definitions that negate a union() with not_() or supply fallback values with | no longer fail to compile when deploying a model.

  • If you force two deployment outputs that depend on each other onto different reasoners, deployment now fails with a clear ConflictingForcedReasoners error that names the outputs and how to fix them, instead of a raw internal error. You set an output's reasoner with deployment.outputs.overrides.

  • When rai models list can't read the model-management schema because of your role's privileges, the error now recommends the correct GRANT USAGE statements instead of an APPLY ON TAG grant that didn't fix the problem.

  • After running the rai models teardown CLI command with the --force option, the follow-up message no longer points you to unnecessary or unavailable commands.

  • Calling a concept with keyword arguments, such as Movie(title="The Matrix") instead of Movie.lookup(title="The Matrix"), now raises a clear Invalid usage error right away instead of failing at query time with a confusing AssertionError.

  • Deploying a concept whose identity includes another concept that has a composite (multi-field) identity key no longer drops part of that key. Previously the deploy could fail with a NULL result in a non-nullable column error, or store incomplete identities.

  • When you create a decision variable with Problem.solve_for() for a concept that has no identify_by key, querying that variable's solved values now returns the matching rows instead of nothing.

2026.8.17-c5208f8

Native App


Version 2026.8.17-c5208f8 of the RelationalAI Native App is now available!

Note that RelationalAI Native App upgrades are applied automatically and require no action on your part, unless you have opted-in to manual upgrades.

Breaking Changes

  • Creating a data stream on a Snowflake-managed Iceberg table now fails immediately with the error Iceberg tables are not supported for CDC data streams. Previously, the stream was created but Snowflake quarantined it, so changes were never processed. See Prepare your data sources for the source objects that data streams support.

New Features and Enhancements

  • The new api.cleanup_stale_data_streams() procedure lets you delete data streams that haven't been accessed for longer than a time-to-live (TTL) you specify. It takes a TTL in minutes and runs in dry-run mode by default, reporting the data streams it would delete without removing anything. Pass DRY_RUN => FALSE to delete them.

  • The api.data_streams view now includes a last_accessed column that shows when each data stream was last accessed by a transaction. The value is NULL for a data stream that has never been accessed.

Bug Fixes

  • Fixed a rare issue where two internal computations could overwrite each other and affect a query's results.

  • Writing to a Snowflake-managed Iceberg table no longer fails with an Invalid parquet file: non-nullable column ... has null values according to file statistics error.

  • The app now reconnects to Snowflake on its own when its internal access token expires, so operations like reasoner creation no longer get stuck and fail.

  • Fixed an issue that prevented custom aggregations over decimal values, such as FixedDecimal, from returning results.

  • Prediction jobs submitted by PyRel to a predictive reasoner no longer fail with an index out of range in self error when your data contains a category that wasn't seen during training.

  • A query that runs while a model's internal data store is being deleted now reports the accurate error The database does not exist. instead of the misleading Database was closed and this transaction was discarded. Note that "database" here refers to an internal database used by the native app and not a Snowflake database visible in your Snowflake account.