ILLEGAL_FINAL ClickHouse error¶
This error usually means you're trying to use the FINAL keyword in a context where it's not allowed. FINAL is only supported with certain table engines and in specific query contexts.
The ILLEGAL_FINAL
error in ClickHouse (and Tinybird) happens when you try to use the FINAL
keyword in a context where it's not supported. The FINAL
keyword is used to get the latest version of rows in tables with certain engines like ReplacingMergeTree
, but it has specific usage requirements.
What causes this error¶
You'll typically see it when:
- Using FINAL with table engines that don't support it
- Using FINAL in subqueries or CTEs
- Using FINAL with certain table engines
- Using FINAL in JOIN operations incorrectly
- Using FINAL in contexts where it's not allowed
FINAL should be used sparingly due to performance cost; it forces merging of parts. FINAL cannot be combined with arrayJoin or WHERE conditions before FINAL.
Example errors¶
Fails: FINAL with unsupported engine
SELECT * FROM events FINAL WHERE user_id = 123
Fails: FINAL in subquery
SELECT * FROM (SELECT * FROM events FINAL) t
Fails: FINAL in JOIN
SELECT * FROM users JOIN events FINAL ON users.id = events.user_id
Fails: FINAL with wrong syntax
SELECT FINAL * FROM events
How to fix it¶
Use FINAL with supported engines¶
Only use FINAL with engines that support it:
Fix: use with supported engine
SELECT * FROM events_replacing FINAL WHERE user_id = 123
Remove FINAL from unsupported contexts¶
Don't use FINAL in subqueries or CTEs:
Fix: remove FINAL from subquery
SELECT * FROM events WHERE user_id = 123
Use proper FINAL syntax¶
Use FINAL correctly in supported contexts:
Fix: correct FINAL syntax
SELECT * FROM events_replacing FINAL WHERE user_id = 123
Use FINAL at the end of the query. SELECT ... FROM table FINAL WHERE ...
is wrong—WHERE goes after FINAL.
Check table engine¶
Verify the table engine supports FINAL:
Check table engine
SELECT * FROM system.tables WHERE name = 'events'
Common patterns and solutions¶
Using FINAL with ReplacingMergeTree¶
FINAL works with ReplacingMergeTree:
FINAL with ReplacingMergeTree
SELECT * FROM events_replacing FINAL WHERE user_id = 123
Using FINAL with CollapsingMergeTree¶
FINAL works with CollapsingMergeTree:
FINAL with CollapsingMergeTree
SELECT * FROM events_collapsing FINAL WHERE user_id = 123
Using FINAL with VersionedCollapsingMergeTree¶
FINAL works with VersionedCollapsingMergeTree:
FINAL with VersionedCollapsingMergeTree
SELECT * FROM events_versioned FINAL WHERE user_id = 123
Using FINAL with GraphiteMergeTree¶
FINAL works with GraphiteMergeTree:
FINAL with GraphiteMergeTree
SELECT * FROM metrics_graphite FINAL WHERE timestamp >= now() - INTERVAL 1 HOUR
Advanced solutions¶
Using FINAL in complex queries¶
FINAL can be used in complex queries with supported engines:
Complex query with FINAL
SELECT user_id, event_type, timestamp FROM events_replacing FINAL WHERE timestamp >= now() - INTERVAL 1 DAY ORDER BY timestamp DESC
Using FINAL with aggregations¶
FINAL can be used with aggregate functions:
FINAL with aggregations
SELECT user_id, COUNT(*) as event_count FROM events_replacing FINAL GROUP BY user_id
Using FINAL with window functions¶
FINAL can be used with window functions:
FINAL with window functions
SELECT user_id, event_type, ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY timestamp DESC) as row_num FROM events_replacing FINAL
Table engines that support FINAL¶
ReplacingMergeTree¶
For handling updates with version numbers:
ReplacingMergeTree with FINAL
CREATE TABLE events_replacing ( user_id UInt32, event_type String, timestamp DateTime, version UInt32 ) ENGINE = ReplacingMergeTree(version) ORDER BY (user_id, timestamp) SELECT * FROM events_replacing FINAL
CollapsingMergeTree¶
For handling inserts and deletes:
CollapsingMergeTree with FINAL
CREATE TABLE events_collapsing ( user_id UInt32, event_type String, timestamp DateTime, sign Int8 ) ENGINE = CollapsingMergeTree(sign) ORDER BY (user_id, timestamp) SELECT * FROM events_collapsing FINAL
VersionedCollapsingMergeTree¶
For handling versioned collapsing:
VersionedCollapsingMergeTree with FINAL
CREATE TABLE events_versioned ( user_id UInt32, event_type String, timestamp DateTime, version UInt32, sign Int8 ) ENGINE = VersionedCollapsingMergeTree(sign, version) ORDER BY (user_id, timestamp) SELECT * FROM events_versioned FINAL
Table engines that don't support FINAL¶
MergeTree¶
Standard MergeTree doesn't support FINAL:
MergeTree without FINAL
SELECT * FROM events WHERE user_id = 123
SummingMergeTree¶
SummingMergeTree doesn't support FINAL:
SummingMergeTree without FINAL
SELECT * FROM events_summing WHERE user_id = 123
AggregatingMergeTree¶
AggregatingMergeTree doesn't support FINAL:
AggregatingMergeTree without FINAL
SELECT * FROM events_aggregating WHERE user_id = 123
Tinybird-specific notes¶
In Tinybird, this error often occurs when:
- Using FINAL with Data Sources that don't support it
- Using FINAL in Pipes with unsupported table engines
- Using FINAL in Materialized Views incorrectly
- Using FINAL in API endpoints with wrong contexts
To debug in Tinybird:
- Check your Data Source table engine for FINAL support
- Verify Pipe operations don't use FINAL in unsupported contexts
- Test FINAL usage in the Query Builder first
- Use alternative approaches when FINAL isn't supported
Include guidance on using WITH FINAL for certain queries in Tinybird Pipes.
Best practices¶
FINAL usage¶
- Only use FINAL with supported table engines
- Don't use FINAL in subqueries or CTEs
- Use FINAL when you need the latest version of rows
- Consider performance implications of using FINAL
Performance considerations¶
- FINAL can be expensive on large tables
- Consider using appropriate indexes
- Monitor query performance with FINAL
- Use FINAL only when necessary
Error prevention¶
- Check table engine before using FINAL
- Test FINAL usage with sample data
- Use alternative approaches when FINAL isn't supported
- Document FINAL usage requirements