When writing BSL for a Snowflake single model (e.g. a single table), I can query it without an issue. However, when adding joins, I consistently get the error ValueError: Don't know how to handle type <class 'ibis.expr.types.relations.Table'>. I am not sure what is causing it, but Claude suggested a working fix. I will provide a simplified version of yaml semantic layer, code, stacktrace and fix below.
yaml Model
users:
table: users__fact
description: "users fact table"
dimensions:
# Surrogate keys
user_key: _.USER_KEY
program_key: _.PROGRAM_KEY
measures:
user_count: _.USER_KEY.nunique()
joins:
programs:
model: programs
type: one
left_on: PROGRAM_KEY
right_on: PROGRAM_KEY
# Supporting dimension tables
programs:
table: programs_table
dimensions:
program_key: _.PROGRAM_KEY
program: _.PROGRAM
Code
import ibis
from boring_semantic_layer import from_yaml
ibis_con = ibis.snowflake.connect(
user="name@place.com",
account=account,
authenticator="externalbrowser",
warehouse=warehouse,
database=db,
)
tables = {
"users": ibis_con.table("USERS", database=(db, schema).limit(100),
"programs": ibis_con.table("PROGRAMS", database=(db, schema))
}
models = from_yaml("users.yaml", tables=tables)
users_model = models["users"]
activity = (
users_model
.group_by("programs.program")
.aggregate("users.user_count")
.execute()
)
Error
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Cell In[22], [line 5](vscode-notebook-cell:?execution_count=22&line=5)
1 teacher_activity = (
2 users_model
3 .group_by("programs.program")
4 .aggregate("users.user_count")
----> [5](vscode-notebook-cell:?execution_count=22&line=5) .execute()
6 )
File ~/path/to/repo/.venv/lib/python3.12/site-packages/library1/expr.py:260, in SemanticTable.execute(self, **kwargs)
256 def execute(self, **kwargs):
257 # Accept kwargs for ibis compatibility (params, limit, etc)
258 from .ops import _unify_backends
--> 260 return _unify_backends(to_untagged(self)).execute(**kwargs)
File ~/path/to/repo/.venv/lib/python3.12/site-packages/library1/expr.py:110, in to_untagged(expr)
108 def to_untagged(expr):
109 if isinstance(expr, SemanticTable):
--> 110 return expr.op().to_untagged()
File ~/path/to/repo/.venv/lib/python3.12/site-packages/library1/ops.py:2173, in SemanticAggregateOp.to_untagged(self)
2170 # Only use the join optimization if there are no filters after the join
2171 # Otherwise we'd skip the filter operations
2172 if join_op is not None and not collected_filters:
-> 2173 tbl = join_op.to_untagged(parent_requirements=self.required_columns)
File ~/path/to/repo/.venv/lib/python3.12/site-packages/library1/ops.py:3663, in SemanticJoinOp.to_untagged(self, parent_requirements)
3653 right_tbl = (
3654 _to_untagged(self.right)
3655 if not isinstance(self.right, SemanticJoinOp)
3656 else self.right.to_untagged()
3657 )
3659 # Rebind right side's DatabaseTable ops to use the same backend as
3660 # the left side. from_ibis() creates a separate Backend object per
3661 # call; xorq >=0.3.11 raises "Multiple backends found" unless all
3662 # tables in a join share the same backend instance.
-> 3663 left_tbl, right_tbl = self._rebind_join_backends(left_tbl, right_tbl)
File ~/path/to/repo/.venv/lib/python3.12/site-packages/library1/ops.py:3719, in SemanticJoinOp._rebind_join_backends(left_tbl, right_tbl)
3716 from library2.vendor.ibis.expr.operations import relations as xorq_rel
3718 # Find a canonical backend from the left tree.
-> 3719 db_tables = list(walk_nodes((xorq_rel.DatabaseTable,), left_tbl))
3720 canonical = db_tables[0].source if db_tables else None
File ~/path/to/repo/.venv/lib/python3.12/site-packages/library2/common/utils/graph_utils.py:74, in walk_nodes(node_types, expr)
71 def walk_nodes(node_types, expr):
72 # TODO should this function use an ordered set
73 visited = set()
---> 74 to_visit = [to_node(expr)]
File ~/path/to/repo/.venv/lib/python3.12/site-packages/library2/common/utils/graph_utils.py:27, in to_node(maybe_expr)
25 return maybe_expr.op()
26 case _:
---> 27 raise ValueError(f"Don't know how to handle type {type(maybe_expr)}")
ValueError: Don't know how to handle type <class 'ibis.expr.types.relations.Table'>
Workaround
Claude came up with the following workaround:
import ibis
from boring_semantic_layer import from_yaml
from boring_semantic_layer.ops import SemanticJoinOp
# Workaround for BSL bug: _rebind_join_backends lacks try/except for non-xorq backends (e.g. Snowflake)
_orig_rebind = SemanticJoinOp._rebind_join_backends
@staticmethod
def _safe_rebind(left_tbl, right_tbl):
try:
return _orig_rebind(left_tbl, right_tbl)
except Exception:
return left_tbl, right_tbl
SemanticJoinOp._rebind_join_backends = _safe_rebind
pip list
Package Version
---------------------------------------- ------------
appnope 0.1.4
asn1crypto 1.5.1
asttokens 3.0.1
atpublic 7.0.0
attrs 25.4.0
beniget 0.4.2.post1
boring-semantic-layer 0.3.10
boto3 1.42.78
botocore 1.42.78
certifi 2026.2.25
cffi 2.0.0
charset-normalizer 3.4.6
cityhash 0.4.10
click 8.3.1
cloudpickle 3.1.2
comm 0.2.3
cryptography 46.0.6
dask 2025.1.0
debugpy 1.8.20
decorator 5.2.1
duckdb 1.3.2
envyaml 1.10.211231
executing 2.2.1
filelock 3.25.2
fsspec 2026.3.0
gast 0.6.0
geoarrow-types 0.3.0
gitdb 4.0.12
gitpython 3.1.46
googleapis-common-protos 1.73.1
grpcio 1.78.0
ibis-framework 12.0.0
idna 3.11
importlib-metadata 8.7.1
iniconfig 2.3.0
ipykernel 7.2.0
ipython 9.12.0
ipython-pygments-lexers 1.1.1
jaraco-classes 3.4.0
jaraco-context 6.1.2
jaraco-functools 4.4.0
jedi 0.19.2
jmespath 1.1.0
jupyter-client 8.8.0
jupyter-core 5.9.1
keyring 25.7.0
linkify-it-py 2.1.0
locket 1.0.0
markdown-it-py 4.0.0
matplotlib-inline 0.2.1
mdit-py-plugins 0.5.0
mdurl 0.1.2
more-itertools 10.8.0
nest-asyncio 1.6.0
numpy 2.4.3
opentelemetry-api 1.40.0
opentelemetry-exporter-otlp 1.40.0
opentelemetry-exporter-otlp-proto-common 1.40.0
opentelemetry-exporter-otlp-proto-grpc 1.40.0
opentelemetry-exporter-otlp-proto-http 1.40.0
opentelemetry-exporter-prometheus 0.61b0
opentelemetry-proto 1.40.0
opentelemetry-sdk 1.40.0
opentelemetry-semantic-conventions 0.61b0
packaging 26.0
pandas 2.3.3
parso 0.8.6
parsy 2.2
partd 1.4.2
pexpect 4.9.0
platformdirs 4.9.4
pluggy 1.6.0
ply 3.11
prometheus-client 0.24.1
prompt-toolkit 3.0.52
protobuf 6.33.6
psutil 7.2.2
ptyprocess 0.7.0
pure-eval 0.2.3
pyarrow 21.0.0
pyarrow-hotfix 0.7
pycparser 3.0
pygments 2.19.2
pyjwt 2.12.1
pyopenssl 26.0.0
pytest 9.0.2
pytest-mock 3.15.1
python-dateutil 2.9.0.post0
pythran 0.18.1
pytz 2026.1.post1
pyyaml 6.0.3
pyzmq 27.1.0
requests 2.33.0
returns 0.26.0
rich 14.3.3
s3transfer 0.16.0
setuptools 82.0.1
six 1.17.0
smmap 5.0.3
snowflake-connector-python 4.4.0
sortedcontainers 2.4.0
sqlglot 28.6.0
stack-data 0.6.3
structlog 25.5.0
textual 8.2.0
tomlkit 0.14.0
toolz 1.1.0
tornado 6.5.5
traitlets 5.14.3
typing-extensions 4.15.0
tzdata 2025.3
uc-micro-py 2.0.0
urllib3 2.6.3
uv 0.11.2
wcwidth 0.6.0
xorq 0.3.16
xorq-datafusion 0.2.5
zipp 3.23.0
Python 3.12.11
When writing BSL for a Snowflake single model (e.g. a single table), I can query it without an issue. However, when adding joins, I consistently get the error
ValueError: Don't know how to handle type <class 'ibis.expr.types.relations.Table'>. I am not sure what is causing it, but Claude suggested a working fix. I will provide a simplified version of yaml semantic layer, code, stacktrace and fix below.yaml Model
Code
Error
Workaround
Claude came up with the following workaround:
pip list
Python 3.12.11