vitessio/vitess · error · VitessError
VT09003
VT09003
Error message
VT09003: INSERT query does not have primary vindex column '%v' in the column list
What it means
VT09003 is raised by insertSelectPlan in go/vt/vtgate/planbuilder/operators/insert.go:451 when an `INSERT ... SELECT` does not include the primary vindex column in its column list. Vitess must know the primary vindex value to route each row, so the first column vindex's columns must be present in the insert columns.
Source
Thrown at go/vt/vtgate/planbuilder/operators/insert.go:451
insertTbl := insOp.tableTarget()
selTables := TablesUsed(selOp)
if slices.Contains(selTables, insertTbl) {
insertSelect.ForceNonStreaming = true
}
if len(insOp.ColVindexes) == 0 {
return insertSelect
}
colVindexes := insOp.ColVindexes
vv := make([][]int, len(colVindexes))
for idx, colVindex := range colVindexes {
for _, col := range colVindex.Columns {
checkAndErrIfVindexChanging(sqlparser.UpdateExprs(ins.OnDup), col)
colNum := findColumn(ins, col)
// sharding column values should be provided in the insert.
if colNum == -1 && idx == 0 {
panic(vterrors.VT09003(col))
}
vv[idx] = append(vv[idx], colNum)
}
}
insOp.VindexValueOffset = vv
return insertSelect
}
func columnMismatch(gen *Generate, ins *sqlparser.Insert, sel sqlparser.TableStatement) bool {
origColCount := len(ins.Columns)
if gen != nil && gen.added {
// One column got added to the insert query ast for auto increment column.
// adjusting it here for comparison.
origColCount--
}
if origColCount < sel.GetColumnCount() {
return true
}View on GitHub (pinned to 01a25a7d17)
Solutions
- Add the primary vindex column to the INSERT column list and supply its value in the SELECT
- If the column is auto-increment, omit it from the column list entirely so modifyForAutoinc handles generation
- Confirm which column(s) form the first (primary) column vindex in the vschema
Example fix
// before INSERT INTO t (name) SELECT name FROM other; // after INSERT INTO t (id, name) SELECT other_id, name FROM other;
Defensive patterns
Strategy: validation
Validate before calling
// Check the primary vindex column is present in the INSERT column list
const primaryVindexCols = vschema.tables['t'].column_vindexes[0].columns;
const missing = primaryVindexCols.filter(c => !insertCols.includes(c));
if (missing.length) throw new Error('primary vindex columns missing from INSERT: ' + missing.join(',')); Type guard
function hasPrimaryVindexColumns(insertCols, vindexes) {
const primary = vindexes[0].columns || [vindexes[0].column];
return primary.every(c => insertCols.map(x => x.toLowerCase()).includes(c.toLowerCase()));
} Try / catch
try {
await vtgate.execute(sql, args);
} catch (e) {
if (String(e).includes('VT09003')) {
throw new Error('Add the primary vindex column to the INSERT column list and supply it in the SELECT');
}
throw e;
} Prevention
- Document the primary vindex columns of every sharded table
- Include primary-vindex columns explicitly in all INSERT..SELECT statements
- Omit auto-increment primary keys instead of supplying them ad hoc
When it happens
Trigger: INSERT INTO t (a, b) SELECT ... where t's primary vindex column is `id` and `id` is missing from the column list (findColumn returns -1 for idx == 0).
Common situations: Assuming Vitess will auto-generate the sharding/primary key in INSERT..SELECT; copying column lists from single-shard MySQL code to sharded Vitess tables; vschema primary vindex changed to a different column.
Related errors
- cannot find column to use to find keyspace_id for table %v
- cannot map vindex to unique keyspace id: %v
- VT09001
- one or two tables must be specified
- at least one table must be specified
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/cdab2155d94e692a.
Report an issue: GitHub.