Home › Database › Cassandra Asks for ALLOW FILTERING on a Clustering Key? Here's Why
Intermediate 3 min · November 05, 2026

Cassandra Asks for ALLOW FILTERING on a Clustering Key? Here's Why

Why Cassandra demands ALLOW FILTERING (or says a clustering column cannot be restricted) even though the column is a clustering key: clustering columns must.

N
Naren Founder & Principal Engineer

20+ years shipping high-throughput database systems. Lessons pulled from things that broke in production.

Follow
✓ Production
production tested
November 05, 2026
last updated
2,128
articles · all by Naren
Before you start⏱ 9 min
  • ✓Basic Cassandra CQL
  • ✓Partition and clustering keys
 ● Production Incident 🔎 Debug Guide
⚡Quick Answer
  • Being a clustering key doesn't make a column independently searchable.
  • Clustering columns are sorted in order; Cassandra can only seek using them left to right, after the full partition key.
  • Skipping an earlier clustering column (or using a range on it) means filtering: Cassandra 3.6+ asks for ALLOW FILTERING; older versions say the column cannot be restricted as preceding column is not restricted.
  • Fix: restrict the preceding columns, reorder the clustering key to match the query, or create a table designed for this query.
  • ALLOW FILTERING inside one small partition is acceptable; without the partition key it scans the whole cluster.
✦ Definition~90s read
What is Cassandra ALLOW FILTERING on a Clustering Key?

Cassandra only reads a clustering column efficiently when the partition key is given and every clustering column before it is restricted with equality. Skip one, and the query needs filtering, so Cassandra asks for ALLOW FILTERING (3.6+) or rejects it outright (older versions).

★
A clustering key is like the sort order of a phone book: by surname, then first name.
Plain-English First

A clustering key is like the sort order of a phone book: by surname, then first name. You can jump straight to "Smith, John". But asking for everyone called "John" without a surname means reading every page, even though first name is part of the sort order. Cassandra makes you say ALLOW FILTERING to admit you're reading every page.

You defined PRIMARY KEY ((tenant_id), created_at, event_id). event_id is a clustering key, so querying WHERE tenant_id = ? AND event_id = ? should be fast, right? Instead Cassandra replies: Cannot execute this query as it might involve data filtering and thus may have unpredictable performance. If you want to execute this query despite the performance unpredictability, use ALLOW FILTERING. On older clusters the message is different: PRIMARY KEY column "event_id" cannot be restricted as preceding column "created_at" is not restricted. Both mean the same thing, and the reason is how Cassandra stores rows on disk.

How Clustering Columns Are Stored

Inside a partition, Cassandra stores rows sorted by the clustering columns in the order you declared them. With PRIMARY KEY ((tenant_id), created_at, event_id), rows are sorted by created_at first, then by event_id within each created_at.

That sort order is what makes reads fast: Cassandra can seek to an exact created_at, then to an exact event_id within it. It can't seek to an event_id on its own, because event_ids are scattered across every created_at.

schema.cqlSQL
1
2
3
4
5
6
7
8
CREATE TABLE tenant_events (
    tenant_id  text,
    created_at date,
    event_id   text,
    payload    text,
    PRIMARY KEY ((tenant_id), created_at, event_id)
);
-- Within a tenant, rows are sorted by created_at, then event_id
Mental Model
Phone book order
Surname, then first name. You can find 'Smith, John' instantly, but not every 'John'.
🎯 Key Takeaway
Clustering columns are a sort order, not independent indexes.

The Query That Triggers It

Restricting event_id without created_at skips the first clustering column. Cassandra would have to read the whole partition and filter rows, so it refuses unless you opt in.

fails.cqlSQL
1
2
3
4
5
6
7
8
9
10
11
12
-- Skips created_at, the first clustering column
SELECT * FROM tenant_events
WHERE tenant_id = 't-9921' AND event_id = 'evt_88320';

-- Cassandra 3.6+:
-- InvalidRequest: Cannot execute this query as it might involve data filtering
-- and thus may have unpredictable performance. If you want to execute this query
-- despite the performance unpredictability, use ALLOW FILTERING

-- Cassandra before 3.6:
-- PRIMARY KEY column "event_id" cannot be restricted as preceding column
-- "created_at" is not restricted
🔥Why two different messages?
Cassandra 3.6 (CASSANDRA-11310) added support for filtering on clustering columns. Before that, the query was simply invalid; since then it's allowed, but only with ALLOW FILTERING.
🎯 Key Takeaway
Skipping a preceding clustering column means filtering.

The Rules for Clustering Columns

  1. Restrict every partition key column with = (or IN).
  2. Restrict clustering columns from the left, without gaps.
  3. Use = on all of them except the last one you restrict, which may use a range (<, >, <=, >=).

A range on created_at followed by a restriction on event_id breaks rule 3, and so does any gap.

works.cqlSQL
1
2
3
4
5
6
7
8
9
10
-- Uses both clustering columns in order: direct read
SELECT * FROM tenant_events
WHERE tenant_id = 't-9921'
  AND created_at = '2026-11-05'
  AND event_id = 'evt_88320';

-- Range on the last restricted clustering column: also fine
SELECT * FROM tenant_events
WHERE tenant_id = 't-9921'
  AND created_at >= '2026-11-01' AND created_at < '2026-11-06';
🎯 Key Takeaway
Partition key first, then clustering columns left to right, range only on the last.

When ALLOW FILTERING Is Acceptable

ALLOW FILTERING doesn't make the query faster; it just lets it run. Its cost depends on how much data must be read:

  • With the full partition key: Cassandra reads only that partition and filters it. Acceptable when partitions are small and bounded.
  • Without the partition key: Cassandra scans data across the whole cluster. Avoid in application code; it degrades as data grows and can time out.
⚠ Tests lie here
Filtering inside a partition is fast with test data and slow when a real partition holds millions of rows. Check your largest partition size before relying on it.
🎯 Key Takeaway
ALLOW FILTERING is fine only when the data it reads is small and bounded.

Fixes That Avoid Filtering

  1. Supply the missing column, if the caller knows it.
  2. Reorder the clustering key so the column you query by comes first, if that's the main access pattern.
  3. Add a query table: Cassandra data modelling is query-first, so a second table keyed for this lookup is the standard answer. Write to both, usually in a logged batch.
  4. Use an index: Storage-Attached Indexing (SAI, in Cassandra 5.0 and DataStax Astra) or a secondary index can serve some lookups, best within a partition. Materialized views exist but are experimental and disabled by default since Cassandra 4.0.
query_table.cqlSQL
1
2
3
4
5
6
7
8
9
10
CREATE TABLE tenant_events_by_id (
    tenant_id  text,
    event_id   text,
    created_at date,
    payload    text,
    PRIMARY KEY ((tenant_id), event_id)
);

SELECT * FROM tenant_events_by_id
WHERE tenant_id = 't-9921' AND event_id = 'evt_88320';
🎯 Key Takeaway
A table per query pattern is the Cassandra-native fix.
● Production incidentPOST-MORTEMseverity: high

The Lookup That Turned Into a Partition Scan

Symptom
Lookups by event_id worked for small tenants but hit read timeouts for the largest ones.
Assumption
Because event_id was part of the primary key, the team assumed the lookup used the key and that ALLOW FILTERING was harmless.
Root cause
event_id was the second clustering column. Without created_at, Cassandra had to read every row in the tenant's partition and filter them. Large tenants had millions of rows per partition.
Fix
Created an events_by_id table keyed on ((tenant_id), event_id) and wrote to both tables. The lookup became a direct read.
Key lesson
  • Clustering columns only help left to right.
  • ALLOW FILTERING cost grows with partition size: fine in tests, slow in production.
  • Model one table per query pattern.
Production debug guideWork out which restriction Cassandra can't use4 entries
Symptom · 01
Asks for ALLOW FILTERING on a clustering column
→
Fix
Run DESCRIBE TABLE and check every clustering column before it is restricted with = in your WHERE clause.
Symptom · 02
cannot be restricted as preceding column is not restricted
→
Fix
Same cause on Cassandra before 3.6; restrict the preceding column or change the model.
Symptom · 03
Range on one clustering column, equality on a later one
→
Fix
Only the last restricted clustering column may use a range; reorder the clustering key or split the query.
Symptom · 04
Query has no partition key at all
→
Fix
This is a full-cluster scan; never ship it with ALLOW FILTERING. Create a table keyed for this query.
⚙ Quick Reference
4 commands from this guide
FileCommand / CodePurpose
schema.cqlCREATE TABLE tenant_events (How Clustering Columns Are Stored
fails.cqlSELECT * FROM tenant_eventsThe Query That Triggers It
works.cqlSELECT * FROM tenant_eventsThe Rules for Clustering Columns
query_table.cqlCREATE TABLE tenant_events_by_id (Fixes That Avoid Filtering

Key takeaways

1
Clustering columns are a sort order, used left to right after the partition key.
2
Skipping a preceding clustering column requires filtering.
3
3.6+ asks for ALLOW FILTERING; older versions reject the query.
4
Only the last restricted clustering column may use a range.
5
Prefer a query-specific table over ALLOW FILTERING.

Common mistakes to avoid

3 patterns
×

Adding ALLOW FILTERING to silence the error

Symptom
Queries pass in tests and time out on large partitions or without a partition key.
Fix
Restrict the preceding columns or create a table for the query.
×

Assuming every primary key column is searchable on its own

Symptom
Surprise errors on clustering columns that aren't first.
Fix
Remember clustering columns work left to right, after the partition key.
×

Ranging on an early clustering column, then filtering a later one

Symptom
Same ALLOW FILTERING error, even though all columns are restricted.
Fix
Only the last restricted clustering column may use a range.
INTERVIEW PREP · PRACTICE MODE

Interview Questions on This Topic

Q01SENIOR
Why can't Cassandra query a second clustering column directly?
Q02SENIOR
When is ALLOW FILTERING acceptable in production?
Q01 of 02SENIOR

Why can't Cassandra query a second clustering column directly?

ANSWER
Rows in a partition are sorted by the clustering columns in declared order, so Cassandra can only seek through them left to right. Without the preceding column it would have to scan and filter the partition, which needs ALLOW FILTERING.
FAQ · 3 QUESTIONS

Frequently Asked Questions

01
Why does Cassandra ask for ALLOW FILTERING when my column is a clustering key?
02
Is ALLOW FILTERING bad?
03
What does 'cannot be restricted as preceding column is not restricted' mean?
N
Naren Founder & Principal Engineer

20+ years shipping high-throughput database systems. Lessons pulled from things that broke in production.

Follow
✓ Verified
production tested
November 05, 2026
last updated
2,128
articles · all by Naren
🔥

That's Cassandra. Mark it forged?

3 min read · try the examples if you haven't

←
Previous
Cassandra vs MongoDB — When to Use Which
5 / 5 · Cassandra
Next
Introduction to Graph Databases and Neo4j
→