vitessio/vitess · error · VitessError

VT09004

VT09004

Error message

VT09004: INSERT should contain column list or the table should have authoritative columns in vschema

What it means

VT09004 is raised by createInsertOperator in go/vt/vtgate/planbuilder/operators/insert.go:382 when an INSERT omits its column list AND the target table's vschema entry is not marked ColumnListAuthoritative. Without a column list or an authoritative column list, Vitess cannot map each value to a column and cannot populate the insert plan.

Source

Thrown at go/vt/vtgate/planbuilder/operators/insert.go:382

	}

	insOp := &Insert{
		VTable: vTbl,
		AST:    insStmt,
	}
	route := &Route{
		unaryOperator: newUnaryOp(insOp),
		Routing:       routing,
	}

	// Table column list is nil then add all the columns
	// If the column list is empty then add only the auto-inc column and
	// this happens on calling modifyForAutoinc
	if insStmt.Columns == nil && valuesProvided(insStmt.Rows) {
		if vTbl.ColumnListAuthoritative {
			insStmt = populateInsertColumnlist(insStmt, vTbl)
		} else {
			panic(vterrors.VT09004())
		}
	}

	// modify column list or values for autoincrement column.
	autoIncGen := modifyForAutoinc(ctx, insStmt, vTbl)
	insOp.AutoIncrement = autoIncGen

	// set insert ignore.
	insOp.Ignore = bool(insStmt.Ignore) || insStmt.OnDup != nil

	insOp.ColVindexes = getColVindexes(insOp)
	switch rows := insStmt.Rows.(type) {
	case sqlparser.Values:
		op = route
		route.Source = insertRowsPlan(ctx, insOp, insStmt, rows)
	case sqlparser.TableStatement:
		op = insertSelectPlan(ctx, insOp, route, insStmt, rows)
	}

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Rewrite the INSERT to include an explicit column list: INSERT INTO t (col1, col2) VALUES (...)
  2. Set `column_list_authoritative: true` on the table's vschema definition if the column list is complete and stable
  3. Resync the vschema with the physical table schema before enabling authoritative columns

Example fix

// before
INSERT INTO users VALUES (1, 'alice');
// after
INSERT INTO users (id, name) VALUES (1, 'alice');
Defensive patterns

Strategy: validation

Validate before calling

// Require an explicit column list for inserts into Vitess tables
const insertRe = /^INSERT\s+INTO\s+[`\w.]+\s*VALUES/i;
if (insertRe.test(sql)) {
  throw new Error('INSERT must include an explicit column list');
}

Type guard

function hasColumnList(insertAst) {
  return Array.isArray(insertAst.columns) && insertAst.columns.length > 0;
}

Try / catch

try {
  await vtgate.execute(sql, args);
} catch (e) {
  if (String(e).includes('VT09004')) {
    throw new Error('Add a column list to the INSERT or set column_list_authoritative in the vschema: ' + e.message);
  }
  throw e;
}

Prevention

When it happens

Trigger: Executing `INSERT INTO t VALUES (...)` (no column list, rows provided) where the vschema table definition for t lacks `column_list_authoritative: true`.

Common situations: Legacy SQL written without explicit column lists being pointed at Vitess; vschema (JSON) files migrated manually without setting column_list_authoritative; tables whose physical schema can change so authoritative lists were intentionally avoided.

Related errors


AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01). Data as JSON: /api/errors/8a03d736fdbec1b8. Report an issue: GitHub.