apache/cassandra · warning

prepared statements discarded in the last minute because…

Error message

{} prepared statements discarded in the last minute because cache limit reached ({} MiB)

What it means

QueryProcessor's scheduled task warns when prepared statements had to be evicted from the in-memory prepared-statement cache during the last minute because the cache hit its configured size limit (prepared_statements_cache_size_mb). Evicted statements must be re-prepared by clients, adding latency and load.

Solutions

  1. Increase prepared_statements_cache_size_mb in cassandra.yaml (or set to 0 for auto heuristic) and restart
  2. Fix clients to use bind variables/parameters instead of string-interpolated unique queries
  3. Monitor statement churn and reduce per-partition key IN lists that expand into many unique statements

Example fix

# cassandra.yaml
# before
prepared_statements_cache_size_mb: 16
# after
prepared_statements_cache_size_mb: 256
Defensive patterns

Strategy: validation

Validate before calling

// Client-side: detect query-shape churn
const uniqueTemplates = new Set();
function guard(query) {
  const tpl = query.replace(/\d+/g, '?').replace(/'[^']*'/g, '?');
  if (uniqueTemplates.size > 10000) throw new Error('statement churn too high');
  uniqueTemplates.add(tpl);
}

Prevention

When it happens

Trigger: Client drivers preparing more unique statements than fit in DatabaseDescriptor.getPreparedStatementsCacheSizeMiB(); the per-minute scheduled job in QueryProcessor detects evictions > 0 and logs the warning.

Common situations: Applications generating unbounded unique statements (e.g. concatenating IDs/values into query text instead of using bind markers); undersized cache after a client fleet growth; burst of new schema/queries.

Related errors


AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10). Data as JSON: /api/errors/7241951e1d977a10. Report an issue: GitHub.

Appendix: source

Thrown at src/java/org/apache/cassandra/cql3/QueryProcessor.java:153

    // Size of the prepared statement cache in bytes.
    public static long PREPARED_STATEMENT_CACHE_SIZE_BYTES = capacityToBytes(DatabaseDescriptor.getPreparedStatementsCacheSizeMiB());

    private static final AtomicInteger lastMinuteEvictionsCount = new AtomicInteger(0);

    static
    {
        preparedStatements = Caffeine.newBuilder()
                             .executor(ImmediateExecutor.INSTANCE)
                             .maximumWeight(PREPARED_STATEMENT_CACHE_SIZE_BYTES)
                             .weigher(QueryProcessor::getSizeOfPreparedStatementForCache)
                             .removalListener((key, prepared, cause) -> evictPreparedStatement(key, cause))
                             .build();

        ScheduledExecutors.scheduledTasks.scheduleAtFixedRate(() -> {
            long count = lastMinuteEvictionsCount.getAndSet(0);
            if (count > 0)
                logger.warn("{} prepared statements discarded in the last minute because cache limit reached ({} MiB)",
                            count,
                            DatabaseDescriptor.getPreparedStatementsCacheSizeMiB());
        }, 1, 1, TimeUnit.MINUTES);

        logger.info("Initialized prepared statement caches with {} MiB",
                    DatabaseDescriptor.getPreparedStatementsCacheSizeMiB());
    }

    private static void evictPreparedStatement(MD5Digest key, RemovalCause cause)
    {
        if (cause.wasEvicted())
        {
            metrics.preparedStatementsEvicted.inc();
            lastMinuteEvictionsCount.incrementAndGet();
            SystemKeyspace.removePreparedStatement(key);
        }
    }

View on GitHub (pinned to 88fd0f6a0e)