{"record":{"id":"576234a3321644ff","repo":"vitessio/vitess","slug":"vt09017-576234","errorCode":"VT09017","errorMessage":"INSERT with a target destination is not allowed","messagePattern":"INSERT with a target destination is not allowed","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/vtgate/planbuilder/operators/route.go","lineNumber":418,"sourceCode":"\t)\n}\n\nfunc createTargetedRouting(ctx *plancontext.PlanningContext, target key.ShardDestination, tabletType topodatapb.TabletType, vschemaTable *vindexes.BaseTable) Routing {\n\tswitch ctx.Statement.(type) {\n\tcase *sqlparser.Update:\n\t\tif tabletType != topodatapb.TabletType_PRIMARY {\n\t\t\tpanic(vterrors.VT09002(\"update\"))\n\t\t}\n\tcase *sqlparser.Delete:\n\t\tif tabletType != topodatapb.TabletType_PRIMARY {\n\t\t\tpanic(vterrors.VT09002(\"delete\"))\n\t\t}\n\tcase *sqlparser.Insert:\n\t\tif tabletType != topodatapb.TabletType_PRIMARY {\n\t\t\tpanic(vterrors.VT09002(\"insert\"))\n\t\t}\n\t\tif target != nil {\n\t\t\tpanic(vterrors.VT09017(\"INSERT with a target destination is not allowed\"))\n\t\t}\n\tcase sqlparser.SelectStatement:\n\t\tif target != nil {\n\t\t\tpanic(vterrors.VT09017(\"SELECT with a target destination is not allowed\"))\n\t\t}\n\t}\n\n\tif target != nil {\n\t\treturn &TargetedRouting{\n\t\t\tkeyspace:          vschemaTable.Keyspace,\n\t\t\tTargetDestination: target,\n\t\t}\n\t}\n\treturn nil\n}\n\n// createRouteFromTable creates a route from the given VSchema table.\nfunc createRouteFromVSchemaTable(","sourceCodeStart":400,"sourceCodeEnd":436,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/vtgate/planbuilder/operators/route.go#L400-L436","documentation":"VT09017 indicates an INSERT statement with an explicitly targeted destination, which Vitess does not allow. Unlike UPDATE/DELETE, INSERTs cannot be pinned to a destination target at all — routing must be derived from the vindex.","triggerScenarios":"Running an INSERT (e.g. `INSERT INTO ks.t ...`) while a target destination is set (USE `ks:shard-0` / `@shard` style target), so target != nil in the Insert case of createTargetedRouting.","commonSituations":"Application sets a shard-specific target to help routing and then performs an INSERT; migration scripts that set explicit shard targets before loading data.","solutions":["Remove the target destination before executing the INSERT and let vindex-based routing pick the shard","Split the workflow: do reads/targeted queries with the target, then reset the target for INSERTs","Use `USE ks` (keyspace only) instead of a shard destination"],"exampleFix":"// before\nUSE ks:-80;\nINSERT INTO t (id) VALUES (5); -- VT09017\n// after\nUSE ks;\nINSERT INTO t (id) VALUES (5); -- routed by primary vindex","handlingStrategy":"validation","validationCode":"// ensure no shard/destination qualifier is active before INSERT\nif strings.Contains(currentTarget, \":\") || strings.Contains(currentTarget, \"@\") {\n    conn.Execute(\"USE ks\", nil) // keyspace only, no destination\n}\nconn.Execute(\"INSERT INTO t (id) VALUES (5)\", nil)","typeGuard":null,"tryCatchPattern":"_, err := conn.Execute(\"INSERT INTO t (id) VALUES (5)\", nil)\nif err != nil && strings.Contains(err.Error(), \"VT09017\") {\n    conn.Execute(\"USE ks\", nil)\n    // retry — vindex routing picks the shard\n}","preventionTips":["Never set shard-level targets for sessions that perform INSERTs","Rely on primary vindex routing instead of manual shard pinning for writes","Reset the target (`USE ks`) after targeted maintenance work"],"tags":["vtgate","insert","targeted-routing","unsupported"],"backgroundTag":"insert-with-target-destination","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}