ClickHouse Version Compatibility#
Overview#
Langfuse manages ClickHouse version compatibility through three mechanisms: (1) automatic version detection at startup that injects per-query optimizer settings, (2) manual environment variable overrides, and (3) image version pinning in compose files. The root problem is ClickHouse's experimental query analyzer (enable_analyzer=1), which became default in 25.x/26.x and breaks several of Langfuse's query patterns.
The Root Problem: Analyzer Behavior Changes#
ClickHouse's new query analyzer (enabled by default from ~25.x/26.x) causes two distinct failure modes in Langfuse:
-
NOT_FOUND_COLUMN_IN_BLOCKerrors β The analyzer incorrectly transformsANDkeyword conditions into internaland(...)function-call identifiers whenFINAL+LEFT JOINare combined. This breaks the Scores and Observations queries, manifesting as 500 errors on the scores page and thescores.allAPI. -
CAST AS Maptype mismatches β Thetraces.metricsquery usingORDER BY ... LIMIT 1 BY id, project_idfor deduplication triggers a type-inference bug in the analyzer, causing failures withUnsupported types to CAST AS Maperrors after upgrading to ClickHouse 25.12.
The query_plan_optimize_lazy_materialization optimizer is the proximate cause β enabled by default from ClickHouse 25.4.0 onward, it interacts badly with specific query shapes Langfuse uses.
Automatic Version Detection (Primary Mitigation)#
PR #14187 introduced compatibility.ts β the central module for version-aware ClickHouse configuration.
How it works:
- At startup,
initializeClickhouseCompatibility()runsSELECT version()against ClickHouse. - The returned version string is parsed and evaluated against
CLICKHOUSE_COMPATIBILITY_RULES. - Currently, the single defined rule is
disable-lazy-materialization: for versions β₯ 25.4.0, it injectsquery_plan_optimize_lazy_materialization: 0into every client connection'sclickhouse_settings. - The detected version and computed flags are logged via
resolveClickHouseCompatibility()for observability β including whether each rule matched and was applied.
The result is cached module-level in detectedClickHouseVersion so version detection runs only once per process lifetime.
This initialization runs before the application accepts requests in both web (web/src/initialize.ts) and worker (worker/src/index.ts) entry points.
Environment Variable Control#
The behavior is governed by CLICKHOUSE_DISABLE_LAZY_MATERIALIZATION (defined in packages/shared/src/server/clickhouse/compatibility.ts):
| Value | Behavior |
|---|---|
auto (default) | Auto-detect via version check; apply if β₯ 25.4.0 |
true | Always inject query_plan_optimize_lazy_materialization: 0 |
false | Never inject (disables the workaround entirely) |
Setting CLICKHOUSE_DISABLE_LAZY_MATERIALIZATION=true is the recommended manual workaround for self-hosters running ClickHouse 25.x/26.x before upgrading Langfuse to a version with auto-detection.
Version Pinning#
PR #14563 pinned the docker-compose.yml ClickHouse image to clickhouse-server:24.3 as a short-term safeguard to prevent users from accidentally pulling ClickHouse 26.x. The snapshot of docker-compose.yml at commit 471e150a shows the image still unpinned (docker.io/clickhouse/clickhouse-server with no tag) β check the current main branch file for the latest state.
CI Test Matrix#
PR #14066 established a three-way version matrix in CI to catch version regressions proactively:
- 24.3 β minimum supported baseline (
docker-compose.dev-azure.yml) - 25.12 β current Langfuse Cloud version (
docker-compose.dev.yml) - 26.6 β latest release (
docker-compose.dev-redis-cluster.yml), requiringCLICKHOUSE_DISABLE_LAZY_MATERIALIZATION=true
Known Limitations#
- Cluster/Distributed tables: The automatic compatibility detection does not fully resolve issues on ClickHouse cluster setups using Distributed tables, because the analyzer behaves differently in that context.
- Query-level fixes: For the
traces.metricscase, the preferred long-term fix is restructuring the query (PR #14432 wraps the problematic subquery) rather than relying solely on optimizer settings.
Key Files#
| File | Purpose |
|---|---|
packages/shared/src/server/clickhouse/compatibility.ts | Version detection, rule engine, compatibility settings resolution |
packages/shared/src/server/clickhouse/client.ts | ClickHouse client manager; injects clickhouse_settings per connection |
packages/shared/src/env.ts | Env schema; CLICKHOUSE_DISABLE_LAZY_MATERIALIZATION |
docker-compose.yml | Production compose file; ClickHouse image version |