apache/shardingsphere · error · UnsupportedUpdatingShardingValueException
31
31
Error message
Can not update sharding value for table '%s'.
What it means
UnsupportedUpdatingShardingValueException is thrown by ShardingInsertRouteContextChecker during INSERT ... ON DUPLICATE KEY UPDATE. The checker builds a second route context from sharding conditions extracted out of the ON DUPLICATE KEY assignment columns; if that route context differs from the original one (ShardingRouteContextCheckUtils.isSameRouteContext false), the UPDATE would move the row to a different shard than the INSERT, which ShardingSphere cannot execute atomically, so it fails with 'Can not update sharding value for table'.
Source
Thrown at features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/route/engine/checker/dml/ShardingInsertRouteContextChecker.java:69
@Override
public void check(final ShardingRule shardingRule, final QueryContext queryContext,
final ShardingSphereDatabase database, final ConfigurationProperties props, final RouteContext routeContext) {
SQLStatementContext sqlStatementContext = queryContext.getSqlStatementContext();
InsertStatement insertStatement = (InsertStatement) sqlStatementContext.getSqlStatement();
Optional<SubquerySegment> insertSelect = insertStatement.getInsertSelect();
String tableName = insertStatement.getTable().map(optional -> optional.getTableName().getIdentifier().getValue()).orElse("");
if (insertSelect.isPresent() && shardingConditions.isNeedMerge()) {
boolean singleRoutingOrSameShardingCondition = routeContext.isSingleRouting() || shardingConditions.isSameShardingCondition();
ShardingSpherePreconditions.checkState(singleRoutingOrSameShardingCondition, () -> new UnsupportedShardingOperationException("INSERT ... SELECT ...", tableName));
}
Collection<ColumnAssignmentSegment> assignments = insertStatement.getOnDuplicateKeyColumns().map(OnDuplicateKeyColumnsSegment::getColumns).orElse(Collections.emptyList());
Optional<ShardingConditions> onDuplicateKeyShardingConditions =
ShardingRouteContextCheckUtils.createShardingConditions(sqlStatementContext, shardingRule, assignments, queryContext.getParameters());
Optional<RouteContext> onDuplicateKeyRouteContext = onDuplicateKeyShardingConditions
.map(optional -> new ShardingStandardRouteEngine(tableName, optional, sqlStatementContext, queryContext.getHintValueContext(), props).route(shardingRule));
if (onDuplicateKeyRouteContext.isPresent() && !ShardingRouteContextCheckUtils.isSameRouteContext(routeContext, onDuplicateKeyRouteContext.get())) {
throw new UnsupportedUpdatingShardingValueException(tableName);
}
if (!routeContext.isSingleRouting()) {
boolean isSingleDataNode = routeContext.getOriginalDataNodes().stream().allMatch(dataNodes -> 1 == dataNodes.size());
ShardingSpherePreconditions.checkState(isSingleDataNode, () -> new DuplicateInsertDataRecordException(shardingConditions, tableName));
}
}
}
View on GitHub (pinned to e952770a21)
Solutions
- Remove the sharding column from the ON DUPLICATE KEY UPDATE assignment list — sharding keys must be immutable.
- If the sharding key must change, split into DELETE (by old key) + INSERT (with new key) inside one application transaction.
- Verify the INSERT values themselves produce a consistent route (all rows in one multi-row INSERT target the same shard).
Example fix
-- before: updating the sharding column INSERT INTO t_order(order_id,cust_id,status) VALUES(?,?,?) ON DUPLICATE KEY UPDATE cust_id=VALUES(cust_id), status=VALUES(status); -- cust_id is the sharding key -> error when VALUES differ -- after: sharding key excluded from the update INSERT INTO t_order(order_id,cust_id,status) VALUES(?,?,?) ON DUPLICATE KEY UPDATE status=VALUES(status);
Defensive patterns
Strategy: validation
Validate before calling
// Strip sharding columns from ON DUPLICATE KEY UPDATE before executing
String shardingColumn = "cust_id";
String insertSql = "INSERT INTO t_order(order_id,cust_id,status) VALUES(?,?,?) ON DUPLICATE KEY UPDATE status=VALUES(status)";
// ensure shardingColumn never appears after 'ON DUPLICATE KEY UPDATE'
String tail = insertSql.substring(insertSql.toUpperCase(Locale.ROOT).indexOf("ON DUPLICATE KEY UPDATE") + 22);
if (tail.toUpperCase(Locale.ROOT).contains(shardingColumn.toUpperCase(Locale.ROOT))) {
throw new IllegalArgumentException("Sharding key must not be updated: " + shardingColumn);
} Try / catch
try {
ps.executeUpdate();
} catch (final UnsupportedUpdatingShardingValueException ex) {
// rewrite to DELETE by old key + INSERT with new key inside one transaction
} Prevention
- Treat sharding keys as immutable columns in your data model and ORM mappings.
- For key changes, use an explicit delete-then-insert transaction with both old and new key values.
When it happens
Trigger: INSERT INTO t (...) VALUES (...) ON DUPLICATE KEY UPDATE <sharding_column> = <new_value> where the new sharding value routes to a different data node/table than the INSERT values. The checker re-routes using conditions derived from the assignments and compares.
Common situations: Upsert code that also 'corrects' the sharding key (e.g. ON DUPLICATE KEY UPDATE tenant_id = VALUES(tenant_id)); changing sharding-column values as part of dedupe logic; migrating single-DB upserts unchanged into a sharded schema.
Related errors
- Sharding algorithm class '%s' should be implement '%s'.
- Could not load class: %s
- Invalid %s, datetime pattern should be '%s', value is '%s'.
- Invalid %s, datetime pattern should be '%s', value is '%s'.
- 40
AI-assisted analysis of apache/shardingsphere@e952770a21 (2026-08-14).
Data as JSON: /api/errors/e5f8f6ceea60a03c.
Report an issue: GitHub.