vitessio/vitess · error

failed to find column name for convert using expression: %v,

Error message

failed to find column name for convert using expression: %v, %v

What it means

For a ConvertUsingExpr, the builder walks the expression to find exactly one inner column name. If the walk returns an error (no column found, or the walk aborted on a qualifier error from the ColName case), the builder wraps it into this error because it cannot construct the rewritten CONVERT expression.

Source

Thrown at go/vt/vttablet/tabletmanager/vreplication/table_plan_builder.go:465

	if expr, ok := aliased.Expr.(*sqlparser.ConvertUsingExpr); ok {
		// Here we find the actual column name in the convert, in case
		// this is a column rename and the AS is the new column.
		// For example, in convert(c1 using utf8mb4) as c2, we want to find
		// c1, because c1 exists in the current table whereas c2 is the renamed column
		// in the desired table.
		var colName sqlparser.IdentifierCI
		err := sqlparser.Walk(func(node sqlparser.SQLNode) (kontinue bool, err error) {
			switch node := node.(type) {
			case *sqlparser.ColName:
				if !node.Qualifier.IsEmpty() {
					return false, fmt.Errorf("unsupported qualifier for column: %v", sqlparser.String(node))
				}
				colName = node.Name
			}
			return true, nil
		}, aliased.Expr)
		if err != nil {
			return nil, fmt.Errorf("failed to find column name for convert using expression: %v, %v", sqlparser.String(aliased.Expr), err)
		}
		selExpr := &sqlparser.ConvertUsingExpr{
			Type: "utf8mb4",
			Expr: &sqlparser.ColName{Name: colName},
		}
		cexpr.expr = expr
		cexpr.operation = opExpr
		tpb.sendSelect.AddSelectExpr(&sqlparser.AliasedExpr{Expr: selExpr, As: as})
		cexpr.references[as.String()] = true
		return cexpr, nil
	}
	if expr, ok := aliased.Expr.(*sqlparser.FuncExpr); ok {
		switch fname := expr.Name.Lowered(); fname {
		case "keyspace_id":
			if len(expr.Exprs) != 0 {
				return nil, fmt.Errorf("unsupported multiple keyspace_id expressions: %v", sqlparser.String(expr))
			}

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Make the CONVERT USING operand a single unqualified column name
  2. Validate the expression parses as CONVERT(col USING utf8mb4) before applying the rule
  3. Fall back to replicating the raw column and converting downstream

Example fix

// before
SELECT CONVERT('literal' USING utf8mb4) AS c FROM t
// after
SELECT CONVERT(col USING utf8mb4) AS c FROM t
Defensive patterns

Strategy: type-guard

Validate before calling

cu, ok := aliased.Expr.(*sqlparser.ConvertUsingExpr)
if !ok { return nil }
if _, ok := cu.Expr.(*sqlparser.ColName); !ok {
    return errors.New("CONVERT USING operand must be a single column")
}

Type guard

func isConvertUsingSingleCol(expr sqlparser.Expr) (*sqlparser.ColName, bool) {
    cu, ok := expr.(*sqlparser.ConvertUsingExpr)
    if !ok { return nil, false }
    col, ok := cu.Expr.(*sqlparser.ColName)
    if !ok || !col.Qualifier.IsEmpty() { return nil, false }
    return col, true
}

Try / catch

if err != nil && strings.Contains(err.Error(), "convert using expression") {
    log.Warn("CONVERT USING must wrap one unqualified column; rewriting rule")
}

Prevention

When it happens

Trigger: `CONVERT USING` expression whose inner expression is not a simple column (e.g. a literal, function call, or qualified name that aborted the walk).

Common situations: Charset-conversion filter rules written against literals or complex expressions instead of a single column.

Related errors


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