{"record":{"id":"3e53409ae142f30b","repo":"apache/cassandra","slug":"accord-transaction-uses-dropped-tables","errorCode":null,"errorMessage":"Accord transaction uses dropped tables","messagePattern":"Accord transaction uses dropped tables","errorType":"validation","errorClass":"InvalidRequestException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/service/accord/AccordResult.java","lineNumber":193,"sourceCode":"            if (txnId != null && txnId.isSyncPoint())\n                AccordAgent.onFailedBarrier(txnId, fail);\n        }\n        else if (isTxnRequest && fail instanceof TopologyMismatch)\n        {\n            // Excluding bugs topology mismatch can occur because a table was dropped in between creating the txn\n            // and executing it.\n            // It could also race with the table stopping/starting being managed by Accord.\n            // The caller can retry if the table indeed exists and is managed by Accord.\n            Set<TableId> txnDroppedTables = txnDroppedTables(keysOrRanges);\n            Tracing.trace(\"Accord returned topology mismatch: \" + fail.getMessage());\n            logger.debug(\"Accord returned topology mismatch\", fail);\n            bookkeeping.markTopologyMismatch();\n            // Throw IRE in case the caller fails to check if the table still exists\n            if (!txnDroppedTables.isEmpty())\n            {\n                Tracing.trace(\"Accord txn uses dropped tables {}\", txnDroppedTables);\n                logger.debug(\"Accord txn uses dropped tables {}\", txnDroppedTables);\n                throw new InvalidRequestException(\"Accord transaction uses dropped tables\");\n            }\n            trySuccess((V) RetryWithNewProtocolResult.instance);\n            return false;\n        }\n        else if (fail instanceof RequestTimeoutException || fail instanceof TimeoutException || fail instanceof CancellationException)\n        {\n            report = bookkeeping.newTimeout(txnId, keysOrRanges);\n        }\n        else\n        {\n            logger.error(\"Unexpected exception\", fail);\n            JVMStabilityInspector.inspectThrowable(fail);\n            report = bookkeeping.newFailed(txnId, keysOrRanges);\n        }\n        report.addSuppressed(fail);\n        if (!super.tryFailure(report))\n            return false;\n","sourceCodeStart":175,"sourceCodeEnd":211,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/service/accord/AccordResult.java#L175-L211","documentation":"Thrown from AccordResult.tryFailure() when an Accord (transactional) transaction fails and the transaction references tables that have been dropped. The exception is raised instead of the original failure so callers cannot silently proceed against a nonexistent table, mirroring the local bookkeeping markTopologyMismatch.","triggerScenarios":"An Accord transaction in flight references a keyspace.table that is dropped (DROP TABLE / DROP KEYSPACE) while the transaction is still executing or retrying; the failure path detects the dropped table and throws InvalidRequestException.","commonSituations":"Application issue of DDL concurrently with Accord transactions; schema migration scripts dropping tables while transactional workloads still issue reads/writes; nodes applying schema changes at different times.","solutions":["Do not drop tables that are still the target of active Accord transactions; quiesce transactional clients first.","Make application code check table existence (or catch InvalidRequestException) before/while running Accord transactions against the table.","Sequence schema changes: stop writers, complete in-flight transactions, then drop the table.","If hit transiently due to schema propagation lag, retry the transaction after schema agreement is reached."],"exampleFix":"// before\nsession.execute(\"DROP TABLE ks.tbl\");\n// after\nawaitNoInFlightAccordTxns(\"ks.tbl\");\nsession.execute(\"DROP TABLE ks.tbl\");","handlingStrategy":"validation","validationCode":"if (driver.getMetadata().getKeyspace(ks)\n        .map(k -> k.getTable(tbl)).isEmpty()) {\n    throw new IllegalStateException(\"Table \" + ks + \".\" + tbl + \" dropped; abort Accord txn\");\n}","typeGuard":"boolean tableExists(Session s, String ks, String tbl) {\n    return s.getMetadata().getKeyspace(ks)\n            .flatMap(k -> k.getTable(tbl)).isPresent();\n}","tryCatchPattern":"try {\n    runAccordTxn(ks, tbl);\n} catch (InvalidRequestException e) {\n    if (e.getMessage().contains(\"dropped tables\")) {\n        recreateOrReroute(ks, tbl);\n    } else throw e;\n}","preventionTips":["Never issue DROP TABLE while Accord transactions target it; drain writers first.","Gate schema migrations behind checks for active transactional workloads.","Catch InvalidRequestException in txn retry loops and check table existence before retrying."],"tags":["accord","dropped-table","invalid-request","schema-change","transactions"],"backgroundTag":"entity-not-found","analyzedSha":"88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1","analyzedAt":"2026-09-10T07:29:22.284Z","contentChangedAt":"2026-09-10T07:29:22.284Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}