vitessio/vitess · error

ErrUnsupportedQuery

ErrUnsupportedQuery

Error message

%w: %s

What it means

VReplicationQueryPlanner.PlanQuery only supports a fixed set of statement types (SELECT, UPDATE, DELETE etc.); any other statement (INSERT, DDL, SET, SHOW, etc.) results in ErrUnsupportedQuery. The planner then wraps the error with the offending statement's SQL text so the developer can see exactly which query was rejected.

Source

Thrown at go/vt/vtctl/workflow/vexec/query_planner.go:134

//
// For DELETE queries, USING, PARTITION, ORDER BY, and LIMIT clauses are not
// supported.
func (planner *VReplicationQueryPlanner) PlanQuery(stmt sqlparser.Statement) (plan QueryPlan, err error) {
	switch stmt := stmt.(type) {
	case *sqlparser.Select:
		plan, err = planner.planSelect(stmt)
	case *sqlparser.Insert:
		err = ErrUnsupportedQuery
	case *sqlparser.Update:
		plan, err = planner.planUpdate(stmt)
	case *sqlparser.Delete:
		plan, err = planner.planDelete(stmt)
	default:
		err = ErrUnsupportedQuery
	}

	if err != nil {
		return nil, fmt.Errorf("%w: %s", err, sqlparser.String(stmt))
	}

	return plan, nil
}

// QueryParams is part of the QueryPlanner interface. A VReplicationQueryPlanner
// will attach the following WHERE clauses iff (a) DBName, Workflow are set,
// respectively, and (b) db_name and workflow do not appear in the original
// query's WHERE clause:
//
//	WHERE (db_name = {{ .DBName }} AND)? (workflow = {{ .Workflow }} AND)? {{ .OriginalWhere }}
func (planner *VReplicationQueryPlanner) QueryParams() QueryParams {
	return QueryParams{
		DBName:         planner.dbname,
		DBNameColumn:   "db_name",
		Workflow:       planner.workflow,
		WorkflowColumn: "workflow",
	}

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Only pass SELECT/UPDATE/DELETE statements supported by VReplicationQueryPlanner to PlanQuery
  2. Rewrite INSERT or DDL work using the appropriate Vitess APIs (e.g. vtctld commands) instead of this planner
  3. Check the wrapped SQL in the error and route unsupported statements elsewhere in your tooling

Example fix

// before
plan, err := planner.PlanQuery(ctx, insertStmt) // unsupported
// after
switch stmt.(type) {
case *sqlparser.Select, *sqlparser.Update, *sqlparser.Delete:
    plan, err = planner.PlanQuery(ctx, stmt)
default:
    return fmt.Errorf("statement type not supported by VReplicationQueryPlanner")
}
Defensive patterns

Strategy: validation

Validate before calling

switch stmt.(type) {
case *sqlparser.Select, *sqlparser.Update, *sqlparser.Delete:
    // supported
default:
    return fmt.Errorf("statement type %T unsupported by VReplicationQueryPlanner", stmt)
}

Type guard

func isPlannableStatement(stmt sqlparser.Statement) bool {
    switch stmt.(type) {
    case *sqlparser.Select, *sqlparser.Update, *sqlparser.Delete:
        return true
    }
    return false
}

Try / catch

plan, err := planner.PlanQuery(ctx, stmt)
if errors.Is(err, vexec.ErrUnsupportedQuery) {
    log.Warnf("skipping unsupported statement: %v", err)
    return nil
}

Prevention

When it happens

Trigger: Calling PlanQuery with a parsed statement that hits the planner's default case — any statement type other than the supported SELECT/UPDATE/DELETE forms (e.g. INSERT, CREATE/ALTER TABLE, SET, SHOW).

Common situations: Passing user-supplied or migration SQL that includes INSERTs or DDL to a VReplication workflow query path; automating workflows over arbitrary SQL scripts; typos routing the wrong statement to the planner.

Related errors


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