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

When processing a convert_tz expression, analyzeExpr walks the expression tree to discover which column it applies to; if the walk returns an error (typically the 'unsupported qualifier for column' error above), this message wraps it, and if no column is found, findColumn also fails into this wrapper, reporting the full expression and the underlying error.

Source

Thrown at go/vt/vttablet/tabletserver/vstreamer/planbuilder.go:939

	case *sqlparser.ConvertUsingExpr:
		// 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 ColExpr{}, fmt.Errorf("failed to find column name for convert using expression: %v, %v", sqlparser.String(aliased.Expr), err)
		}
		colnum, err := findColumn(plan.Table, colName)
		if err != nil {
			return ColExpr{}, err
		}
		field := plan.Table.Fields[colnum]
		plan.setConvertColumnUsingUTF8(field.Name)
		return ColExpr{
			ColNum: colnum,
			Field:  field,
		}, nil
	default:
		log.Info(fmt.Sprintf("Unsupported expression: %v", inner))
		return ColExpr{}, fmt.Errorf("unsupported: %v", sqlparser.String(aliased.Expr))
	}
}

// analyzeInKeyRange allows the following constructs: "in_keyrange('-80')",

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Use an unqualified column inside convert_tz: convert_tz(ts, '%s', ...) as ts.
  2. Alias the expression (as <column_name>) so findColumn can locate it in the table's fields.
  3. Verify the aliased name matches a real column of the streamed table.

Example fix

// before
select convert_tz(t.ts, '+00:00', '+05:30') as ts from t
// after
select convert_tz(ts, '+00:00', '+05:30') as ts from t
Defensive patterns

Strategy: validation

Validate before calling

// ensure convert_tz args contain an unqualified column and the expr is aliased to a real column
if !strings.Contains(expr, "convert_tz") {
    return nil
}
if hasQualifier(expr) {
    return fmt.Errorf("convert_tz must reference an unqualified column: %s", expr)
}
if aliasedTo, ok := aliasOf(expr); !ok || !columnExists(table, aliasedTo) {
    return fmt.Errorf("convert_tz expression must be aliased to an existing column")
}

Type guard

func isAliasedConvertTz(expr string) (string, bool) {
    parts := strings.Split(expr, " as ")
    if len(parts) == 2 && strings.Contains(parts[0], "convert_tz") {
        return strings.TrimSpace(parts[1]), true
    }
    return "", false
}

Try / catch

if err != nil && strings.Contains(err.Error(), "failed to find column name for convert using expression") {
    return fmt.Errorf("make convert_tz reference an unqualified, aliased column: %w", err)
}

Prevention

When it happens

Trigger: A convert_tz(...) select expression whose inner column reference is qualified (e.g. convert_tz(t.ts, ...) as ts) so the walk errors before assigning colName.

Common situations: Qualified columns inside convert_tz in vstream selects; copy-pasted queries with table qualifiers into a vstreamer-based conversion flow.

Related errors


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