vitessio/vitess · error
unsupported construct: %v
Error message
unsupported construct: %v
What it means
Returned by vreplication controller plan building when the statement contains a construct the planner cannot translate into a vreplication plan, wrapping or naming the unsupported construct.
Source
Thrown at go/vt/vttablet/tabletmanager/vreplication/controller_plan.go:189
tableName, err := ins.Table.TableName()
if err != nil {
return nil, err
}
if tableName.Qualifier.String() != sidecar.GetName() && tableName.Qualifier.String() != sidecar.DefaultName {
return nil, fmt.Errorf("invalid database name: %s", tableName.Qualifier.String())
}
switch tableName.Name.String() {
case reshardingJournalTableName:
return &controllerPlan{
opcode: reshardingJournalQuery,
}, nil
case vreplicationTableName:
// no-op
default:
return nil, fmt.Errorf("invalid table name: %s", tableName.Name.String())
}
if ins.Action != sqlparser.InsertAct {
return nil, fmt.Errorf("unsupported construct: %v", sqlparser.String(ins))
}
if ins.Ignore {
return nil, fmt.Errorf("unsupported construct: %v", sqlparser.String(ins))
}
if ins.Partitions != nil {
return nil, fmt.Errorf("unsupported construct: %v", sqlparser.String(ins))
}
if ins.OnDup != nil {
return nil, fmt.Errorf("unsupported construct: %v", sqlparser.String(ins))
}
rows, ok := ins.Rows.(sqlparser.Values)
if !ok {
return nil, fmt.Errorf("unsupported construct: %v", sqlparser.String(ins))
}
idPos := 0
if len(ins.Columns) != 0 {
idPos = -1
for i, col := range ins.Columns {View on GitHub (pinned to 01a25a7d17)
Solutions
- Rewrite as a plain `INSERT INTO _vt.vreplication ...`.
- Use `update _vt.vreplication set ... where id=...` instead of REPLACE to modify existing rows.
- Ensure unique ids so plain INSERT succeeds (vreplication ids are explicit, not auto-increment).
Example fix
// before replace into _vt.vreplication(id, message) values (1, 'x') // after insert into _vt.vreplication(id, message) values (1, 'x')
Defensive patterns
Strategy: validation
Validate before calling
if strings.HasPrefix(strings.ToUpper(stmt), "REPLACE ") {
return fmt.Errorf("REPLACE not supported by vreplication engine; use INSERT or UPDATE")
} Try / catch
plan, err := buildInsertPlan(ins, sidecar)
if err != nil && strings.Contains(err.Error(), "unsupported construct") {
return vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "plain INSERT only; rewrite REPLACE statements")
} Prevention
- Ban REPLACE INTO in scripts that target _vt tables.
- Use explicit INSERT with unique ids; ids are caller-provided, not auto-increment.
- Code-review any generated SQL sent through VExec.
When it happens
Trigger: A `REPLACE INTO _vt.vreplication ...` statement (or other non-InsertAct action) passed to the vreplication engine's exec path.
Common situations: Using MySQL's REPLACE INTO as a shortcut for upsert; generated scripts using REPLACE; translation of application SQL into vexec without adjusting syntax.
Related errors
- unsupported construct: %s
- ErrUnsupportedQuery
- ErrUnsupportedQueryConstruct
- ErrCannotUpdateImmutableColumn
- invalid database name: %s
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/8e769f68c739eb35.
Report an issue: GitHub.