vitessio/vitess · error
VT09002
VT09002
Error message
update
What it means
VT09002 signals an unsupported feature in Vitess. When planning an UPDATE statement routed to an explicit target (e.g. `@primary`, `@replica`, a keyspace:shard target), the target tablet type must be PRIMARY; UPDATE cannot be executed against replica targets.
Source
Thrown at go/vt/vtgate/planbuilder/operators/route.go:407
panic(err)
}
targeted := createTargetedRouting(ctx, target, tabletType, vschemaTable)
return createRouteFromVSchemaTable(
ctx,
queryTable,
vschemaTable,
planAlternates,
targeted,
)
}
func createTargetedRouting(ctx *plancontext.PlanningContext, target key.ShardDestination, tabletType topodatapb.TabletType, vschemaTable *vindexes.BaseTable) Routing {
switch ctx.Statement.(type) {
case *sqlparser.Update:
if tabletType != topodatapb.TabletType_PRIMARY {
panic(vterrors.VT09002("update"))
}
case *sqlparser.Delete:
if tabletType != topodatapb.TabletType_PRIMARY {
panic(vterrors.VT09002("delete"))
}
case *sqlparser.Insert:
if tabletType != topodatapb.TabletType_PRIMARY {
panic(vterrors.VT09002("insert"))
}
if target != nil {
panic(vterrors.VT09017("INSERT with a target destination is not allowed"))
}
case sqlparser.SelectStatement:
if target != nil {
panic(vterrors.VT09017("SELECT with a target destination is not allowed"))
}
}
View on GitHub (pinned to 01a25a7d17)
Solutions
- Issue the UPDATE against the PRIMARY target (e.g. `USE ks@primary` or remove the target qualifier)
- Reset the session target back to primary before running DML
- Fix application routing logic so writes never target replicas
Example fix
// before USE ks@replica; UPDATE t SET a = 1 WHERE id = 5; -- VT09002: update // after USE ks@primary; UPDATE t SET a = 1 WHERE id = 5;
Defensive patterns
Strategy: validation
Validate before calling
-- check current target before DML
SELECT @@vt_target; -- or inspect session target in the driver
// issue DML only when target is primary
if currentTarget != "ks@primary" { conn.Execute("USE ks@primary", nil) } Try / catch
_, err := conn.Execute("UPDATE t SET a=1 WHERE id=5", nil)
if err != nil && strings.Contains(err.Error(), "VT09002") {
conn.Execute("USE ks@primary", nil)
// retry the statement
} Prevention
- Reset session targets after read-only work
- Use separate connections/pools for read (replica) and write (primary) traffic
- Assert target type before issuing DML
When it happens
Trigger: Executing an UPDATE statement with a targeted destination (USE with a target like keyspace@replica, or `@replica`/`@rdonly`/shard target) so createTargetedRouting receives a non-PRIMARY tabletType.
Common situations: Session was switched to a replica/rdonly target (`USE ks@replica`) and the application then issues an UPDATE; misconfigured routing rules pointing DML at non-primary tablets.
Related errors
- VT09002
- VT12001
- cannot map vindex to unique keyspace id: %v
- UnicodeLooseMD5.Map: %v
- UnicodeLooseXXHash.Map: %v
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/5cc2fac60c5e7858.
Report an issue: GitHub.