apache/shardingsphere · error · ShardingDDLRouteException

40

40

Error message

'DROP INDEX' can not route correctly for INDEX '%s'.

What it means

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.

Source

Thrown at features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/route/engine/checker/ddl/ShardingDropIndexRouteContextChecker.java:63

        DropIndexStatement dropIndexStatement = (DropIndexStatement) queryContext.getSqlStatementContext().getSqlStatement();
        Collection<IndexSegment> indexSegments = dropIndexStatement.getIndexes();
        Optional<String> logicTableName = dropIndexStatement.getSimpleTable().map(optional -> optional.getTableName().getIdentifier().getValue());
        if (logicTableName.isPresent()) {
            validateDropIndexRouteUnit(shardingRule, routeContext, indexSegments, logicTableName.get());
        } else {
            String defaultSchemaName = new DatabaseTypeRegistry(queryContext.getSqlStatementContext().getSqlStatement().getDatabaseType()).getDefaultSchemaName(database.getName());
            for (IndexSegment each : indexSegments) {
                ShardingSphereSchema schema = each.getOwner().map(optional -> optional.getIdentifier().getValue()).map(database::getSchema).orElseGet(() -> database.getSchema(defaultSchemaName));
                logicTableName = schema.getAllTables().stream().filter(table -> table.containsIndex(each.getIndexName().getIdentifier().getValue())).findFirst().map(ShardingSphereTable::getName);
                logicTableName.ifPresent(optional -> validateDropIndexRouteUnit(shardingRule, routeContext, indexSegments, optional));
            }
        }
    }
    
    private void validateDropIndexRouteUnit(final ShardingRule shardingRule, final RouteContext routeContext, final Collection<IndexSegment> indexSegments, final String logicTableName) {
        if (ShardingSupportedCheckUtils.isRouteUnitDataNodeDifferentSize(shardingRule, routeContext, logicTableName)) {
            Collection<String> indexNames = indexSegments.stream().map(each -> each.getIndexName().getIdentifier().getValue()).collect(Collectors.toList());
            throw new ShardingDDLRouteException("DROP", "INDEX", indexNames);
        }
    }
}

View on GitHub (pinned to e952770a21)

Solutions

  1. 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.
  2. Verify which logic table owns the index (every schema table is scanned via containsIndex) and check its actualDataNodes configuration for asymmetry.
  3. If the topology is intentionally asymmetric, drop the index directly on each physical database, bypassing ShardingSphere routing.
  4. Check binding table groups: a binding table whose members have different topologies also triggers this path.

Example fix

# before (asymmetric topology triggers error)
tables:
  - logicTable: t_order
    actualDataNodes: ds_0.t_order_0..3
  - logicTable: t_order_item
    actualDataNodes: ds_0.t_order_item_0..1,ds_1.t_order_item_0..1

# after (symmetric per data source)
tables:
  - logicTable: t_order
    actualDataNodes: ds_${0..1}.t_order_${0..3}
  - logicTable: t_order_item
    actualDataNodes: ds_${0..1}.t_order_item_${0..3}
Defensive patterns

Strategy: validation

Validate before calling

// Before issuing DROP INDEX, assert every route unit has the same table count per data source
ShardingTable table = database.getSchema(schemaName).getTable("t_order");
Map<String, Long> perDs = table.getIndexTableDataNodes() == null ? null : null; // conceptual
// practical: inspect the sharding rule's actual data nodes per data source
Map<String, Integer> counts = new HashMap<>();
for (DataNode dn : shardingTable.getActualDataNodes()) {
    counts.merge(dn.getDataSourceName(), 1, Integer::sum);
}
boolean symmetric = new HashSet<>(counts.values()).size() <= 1;
if (!symmetric) { /* align topology or execute DROP INDEX per physical DB */ }

Try / catch

try {
    statement.execute("DROP INDEX idx_order_no ON t_order");
} catch (final ShardingSphereException ex) {
    if (ex.getMessage().contains("'DROP INDEX' can not route correctly")) {
        // fall back: drop the index on each physical data source directly
    } else { throw ex; }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of apache/shardingsphere@e952770a21 (2026-08-14). Data as JSON: /api/errors/029641a09095d2a2. Report an issue: GitHub.