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