{"record":{"id":"029641a09095d2a2","repo":"apache/shardingsphere","slug":"40","errorCode":"40","errorMessage":"'DROP INDEX' can not route correctly for INDEX '%s'.","messagePattern":"'DROP INDEX' can not route correctly for INDEX '(.+?)'\\.","errorType":"exception","errorClass":"ShardingDDLRouteException","httpStatus":null,"severity":"error","filePath":"features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/route/engine/checker/ddl/ShardingDropIndexRouteContextChecker.java","lineNumber":63,"sourceCode":"        DropIndexStatement dropIndexStatement = (DropIndexStatement) queryContext.getSqlStatementContext().getSqlStatement();\n        Collection<IndexSegment> indexSegments = dropIndexStatement.getIndexes();\n        Optional<String> logicTableName = dropIndexStatement.getSimpleTable().map(optional -> optional.getTableName().getIdentifier().getValue());\n        if (logicTableName.isPresent()) {\n            validateDropIndexRouteUnit(shardingRule, routeContext, indexSegments, logicTableName.get());\n        } else {\n            String defaultSchemaName = new DatabaseTypeRegistry(queryContext.getSqlStatementContext().getSqlStatement().getDatabaseType()).getDefaultSchemaName(database.getName());\n            for (IndexSegment each : indexSegments) {\n                ShardingSphereSchema schema = each.getOwner().map(optional -> optional.getIdentifier().getValue()).map(database::getSchema).orElseGet(() -> database.getSchema(defaultSchemaName));\n                logicTableName = schema.getAllTables().stream().filter(table -> table.containsIndex(each.getIndexName().getIdentifier().getValue())).findFirst().map(ShardingSphereTable::getName);\n                logicTableName.ifPresent(optional -> validateDropIndexRouteUnit(shardingRule, routeContext, indexSegments, optional));\n            }\n        }\n    }\n    \n    private void validateDropIndexRouteUnit(final ShardingRule shardingRule, final RouteContext routeContext, final Collection<IndexSegment> indexSegments, final String logicTableName) {\n        if (ShardingSupportedCheckUtils.isRouteUnitDataNodeDifferentSize(shardingRule, routeContext, logicTableName)) {\n            Collection<String> indexNames = indexSegments.stream().map(each -> each.getIndexName().getIdentifier().getValue()).collect(Collectors.toList());\n            throw new ShardingDDLRouteException(\"DROP\", \"INDEX\", indexNames);\n        }\n    }\n}\n","sourceCodeStart":45,"sourceCodeEnd":67,"githubUrl":"https://github.com/apache/shardingsphere/blob/e952770a215630a3659c75d64369168cd3e26b82/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/route/engine/checker/ddl/ShardingDropIndexRouteContextChecker.java#L45-L67","documentation":"Thrown by ShardingDropIndexRouteChecker when a DROP INDEX statement on a sharding (or binding) table produces route units whose table data-node counts differ. ShardingSphere cannot rewrite a DROP INDEX consistently across databases when the target index's logic table does not resolve to the same number of actual tables in every routed data source, so it fails fast instead of dropping only a subset of the index. The index name is resolved to a logic table by scanning every schema table for one that contains the index.","triggerScenarios":"Executing DROP INDEX where the resolved logic table (the table whose metadata contains indexNames) routes to route units with different numbers of table mappers (ShardingSupportedCheckUtils.isRouteUnitDataNodeDifferentSize returns true). Typical with uneven actual-data-nodes per data source for the sharding table, or when the index belongs to a table in a binding group with mismatched topology.","commonSituations":"A sharding table configured with different actual table counts per data source (e.g. ds_0 has 4 tables, ds_1 has 2) and a DROP INDEX issued through Proxy/JDBC; or an index created directly on one physical table so metadata resolution picks a table whose routing is asymmetric across data sources.","solutions":["Make the actual data nodes of the owning sharding table symmetric across all routed data sources (same table count per data source) in the sharding rule, then re-run DROP INDEX.","Verify which logic table owns the index (every schema table is scanned via containsIndex) and check its actualDataNodes configuration for asymmetry.","If the topology is intentionally asymmetric, drop the index directly on each physical database, bypassing ShardingSphere routing.","Check binding table groups: a binding table whose members have different topologies also triggers this path."],"exampleFix":"# before (asymmetric topology triggers error)\ntables:\n  - logicTable: t_order\n    actualDataNodes: ds_0.t_order_0..3\n  - logicTable: t_order_item\n    actualDataNodes: ds_0.t_order_item_0..1,ds_1.t_order_item_0..1\n\n# after (symmetric per data source)\ntables:\n  - logicTable: t_order\n    actualDataNodes: ds_${0..1}.t_order_${0..3}\n  - logicTable: t_order_item\n    actualDataNodes: ds_${0..1}.t_order_item_${0..3}","handlingStrategy":"validation","validationCode":"// Before issuing DROP INDEX, assert every route unit has the same table count per data source\nShardingTable table = database.getSchema(schemaName).getTable(\"t_order\");\nMap<String, Long> perDs = table.getIndexTableDataNodes() == null ? null : null; // conceptual\n// practical: inspect the sharding rule's actual data nodes per data source\nMap<String, Integer> counts = new HashMap<>();\nfor (DataNode dn : shardingTable.getActualDataNodes()) {\n    counts.merge(dn.getDataSourceName(), 1, Integer::sum);\n}\nboolean symmetric = new HashSet<>(counts.values()).size() <= 1;\nif (!symmetric) { /* align topology or execute DROP INDEX per physical DB */ }","typeGuard":null,"tryCatchPattern":"try {\n    statement.execute(\"DROP INDEX idx_order_no ON t_order\");\n} catch (final ShardingSphereException ex) {\n    if (ex.getMessage().contains(\"'DROP INDEX' can not route correctly\")) {\n        // fall back: drop the index on each physical data source directly\n    } else { throw ex; }\n}","preventionTips":["Keep actual data nodes symmetric across data sources for every sharded and binding table.","Run SHOW SHARDING TABLE RULES after topology changes and verify per-data-source table counts match.","Prefer defining indexes through ShardingSphere-routed DDL so metadata and rules stay consistent."],"tags":["sharding","ddl","drop-index","routing","topology"],"backgroundTag":null,"analyzedSha":"e952770a215630a3659c75d64369168cd3e26b82","analyzedAt":"2026-08-14T13:54:53.392Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}