vitessio/vitess · error
invalid table name: %s
Error message
invalid table name: %s
What it means
Returned by vreplication controller plan building when a table name parsed from a routing rule or query construct is not a valid identifier.
Source
Thrown at go/vt/vttablet/tabletmanager/vreplication/controller_plan.go:186
if ins == nil {
return nil, errors.New("BUG: invalid nil INSERT statement found when building VReplication plan")
}
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 := 0View on GitHub (pinned to 01a25a7d17)
Solutions
- Restrict engine-driven INSERTs to _vt.vreplication (and _vt.resharding_journal).
- For internal tables like _vt.copy_state, execute the statement directly on the tablet's MySQL as the vt_dba user.
- Use the documented workflow commands (vtctldclient) instead of mutating internal tables.
- If a new sidecar table needs engine support, add a case in buildInsertPlan upstream.
Example fix
// before insert into _vt.copy_state(vid, uid) values (1, 2) // after — run on tablet MySQL directly, or use a supported table: insert into _vt.vreplication(id, workflow) values (1, 'w')
Defensive patterns
Strategy: validation
Validate before calling
allowed := map[string]bool{"vreplication": true, "resharding_journal": true}
table := tableNameFromInsert(stmt)
if !allowed[table] {
return fmt.Errorf("table %s is not engine-writable; use tablet MySQL directly", table)
} Try / catch
plan, err := buildInsertPlan(ins, sidecar)
if err != nil && strings.Contains(err.Error(), "invalid table name") {
return vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "only _vt.vreplication and _vt.resharding_journal accept engine INSERTs")
} Prevention
- Treat _vt.copy_state and other internal tables as read-only via the engine.
- Manage internal tables only via vtctldclient or direct MySQL as an operator.
- Document which sidecar tables are engine-writable for your team's tooling.
When it happens
Trigger: An INSERT statement against a sidecar table other than vreplication or resharding_journal — e.g. `insert into _vt.copy_state ...` sent through the vreplication engine's plan builder.
Common situations: Operators trying to hand-edit internal bookkeeping tables (copy_state, lag, etc.) via VExec; tooling that assumed all sidecar tables are writable through this path; scripts written for direct-MySQL use repointed at the vreplication engine.
Related errors
- invalid database name: %s
- either source or target shards are missing
- validateWorkflowName.VReplicationExec: <dynamic validation.m
- UnescapeID err: invalid input identifier '%s'
- %w: SQL query is required
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/3a29d7dafa99aa7f.
Report an issue: GitHub.