apache/cassandra · error · InvalidRequestException
Unable to CAS write to denylisted partition
Error message
Unable to CAS write to denylisted partition [0x%s] in %s/%s
What it means
StorageProxy.cas rejects compare-and-set (LWT) writes whose partition key is on the partition denylist. When partition denylisting and denylisted-write rejection are enabled, isKeyPermitted() failing causes an InvalidRequestException so the denied write never enters the Paxos protocol.
Solutions
- Remove the partition from the denylist (via the denylist JMX/mbean or the operational tooling) so the key is permitted again.
- Stop issuing LWT/CAS writes to the denied partition, or redirect the application to a different key.
- If denylisting writes is too aggressive, set cassandra.denylist_writes_enabled=false (or the equivalent yaml option) while keeping denylisting for reads only.
Example fix
// before: CAS write to denied partition UPDATE users USING TTL 60 SET v=? WHERE k=? IF EXISTS; // after: remove key from denylist first (nodetool/jmx denylist removal), or use non-LWT write UPDATE users USING TTL 60 SET v=? WHERE k=?;
Defensive patterns
Strategy: validation
Validate before calling
// check denylist state before issuing a CAS (via operator tooling/jmx)
boolean denied = denylistMbean.isKeyPermitted(keyspace, table, key); // if exposed
if (!denied) throw new IllegalStateException("key is denylisted; skip CAS write"); Try / catch
try {
session.execute(casQuery);
} catch (InvalidRequestException e) {
if (e.getMessage().contains("denylisted partition")) {
// alert ops / route write elsewhere; do not blind-retry
}
} Prevention
- Keep an application-side copy of denylisted keys and skip them proactively.
- Subscribe to ops notifications when denylist entries change.
- Monitor denylistMetrics.writesRejected for unexpected spikes.
When it happens
Trigger: Executing an INSERT ... IF NOT EXISTS / UPDATE ... IF / DELETE ... IF (CAS/LWT) on a partition that was added to the partition denylist while DatabaseDescriptor.getPartitionDenylistEnabled() and getDenylistWritesEnabled() are true.
Common situations: Operators denylisting a problematic partition (e.g. during incident mitigation or bad-data quarantine) while an application keeps issuing conditional writes to it; keyspace/table names in the denylist entry matching the CAS target.
Understand the failure class
Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.
Related errors
- Unable to write to denylisted partition
- Attempted to read a range containing
- Unable to read denylisted partition
- A storage-attached index cannot be created over multiple…
- A TTL must be greater or equal to 0, but was
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/b2af6e6c4acd4fac.
Report an issue: GitHub.
Appendix: source
Thrown at src/java/org/apache/cassandra/service/StorageProxy.java:381
*
* @return null if the operation succeeds in updating the row, or the current values corresponding to conditions.
* (since, if the CAS doesn't succeed, it means the current value do not match the conditions).
*/
public static RowIterator cas(String keyspaceName,
String cfName,
DecoratedKey key,
CASRequest request,
ConsistencyLevel consistencyForPaxos,
ConsistencyLevel consistencyForCommit,
ClientState clientState,
long nowInSeconds,
Dispatcher.RequestTime requestTime)
throws UnavailableException, IsBootstrappingException, RequestFailureException, RequestTimeoutException, InvalidRequestException, CasWriteUnknownResultException
{
if (DatabaseDescriptor.getPartitionDenylistEnabled() && DatabaseDescriptor.getDenylistWritesEnabled() && !partitionDenylist.isKeyPermitted(keyspaceName, cfName, key.getKey()))
{
denylistMetrics.incrementWritesRejected();
throw new InvalidRequestException(String.format("Unable to CAS write to denylisted partition [0x%s] in %s/%s",
key, keyspaceName, cfName));
}
ConsensusAttemptResult lastAttemptResult = null;
do
{
ClusterMetadata cm = ClusterMetadata.current();
TableMetadata metadata = Schema.instance.validateTable(keyspaceName, cfName);
ConsensusRoutingDecision decision = consensusRouting(cm, metadata, key, consistencyForPaxos, requestTime, true);
switch (decision.target)
{
case paxosV2:
lastAttemptResult = Paxos.cas(key,
request,
consistencyForPaxos,
consistencyForCommit,
clientState,
requestTime,View on GitHub (pinned to 88fd0f6a0e)