iflytek/astron-agent · error · ValueError

Column names must be used in UPDATE SET clause

Error message

Column names must be used in UPDATE SET clause: {set_expr}

What it means

_collect_update_keys validates the SET clause of a parsed UPDATE DML statement. Each SET target must be a plain Column identifier; anything else (literals, expressions, function calls) is rejected so column-level permission checks remain possible.

Solutions

  1. Rewrite the SET clause to assign only bare column names and move computation into the WHERE or application layer
  2. Use SET col = <literal> form only
  3. Pre-validate the SQL with the same parser before submitting

Example fix

// before
UPDATE t SET cnt = cnt + 1 WHERE id = 1
// after
UPDATE t SET cnt = 42 WHERE id = 1  -- computed values rejected; use literal per-column SET
Defensive patterns

Strategy: validation

Validate before calling

import sqlglot
stmt = sqlglot.parse_one(sql, read='mysql')
for a in stmt.find_all(sqlglot.exp.Update):
    for eq in a.expressions:
        if not isinstance(eq.this, sqlglot.exp.Column):
            raise ValueError(f'SET target must be a column: {eq.this}')

Type guard

def is_plain_column_update(parsed) -> bool:
    return all(isinstance(eq.this, Column) for eq in parsed.expressions)

Try / catch

try:
    exec_dml(sql)
except ValueError as e:
    if 'SET clause' in str(e): return reject_dml('computed SET values not allowed')
    raise

Prevention

When it happens

Trigger: Executing an UPDATE whose SET clause assigns to expressions rather than bare column names, e.g. SET a = a + 1, SET x = CONCAT(a,b), or quoted/aliased targets the SQLGlot parser does not classify as Column.

Common situations: Users submit DML through the database API that uses computed SET values or raw SQL copied from another database's dialect.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of iflytek/astron-agent@5e758547a8 (2026-09-12). Data as JSON: /api/errors/168f6b523f9fef51. Report an issue: GitHub.

Appendix: source

Thrown at core/memory/database/api/v1/exec_dml.py:643

    return keys_to_validate


def _collect_update_keys(parsed: Any) -> list:
    """Collect key names from UPDATE statements."""
    keys_to_validate = []
    for node in parsed.walk():
        if not isinstance(node, exp.Update):
            continue

        for set_expr in node.expressions:
            if not isinstance(set_expr, exp.EQ):
                continue

            left = set_expr.left
            if isinstance(left, Column):
                keys_to_validate.append(left.name)
            elif not isinstance(left, Column):
                raise ValueError(
                    f"Column names must be used in UPDATE SET clause: {set_expr}"
                )
    return keys_to_validate


def _collect_columns_and_keys(parsed: Any) -> tuple[list, list, list]:
    """Collect column names and key names that need validation."""
    functions_to_validate = _collect_functions_names(parsed)
    columns_to_validate = _collect_column_names(parsed)
    insert_keys = _collect_insert_keys(parsed)
    update_keys = _collect_update_keys(parsed)
    keys_to_validate = insert_keys + update_keys
    return functions_to_validate, columns_to_validate, keys_to_validate


def _validate_comparison_nodes(parsed: Any, uid: str, span_context: Any) -> Any:
    """Validate comparison operation nodes."""
    for node in parsed.walk():

View on GitHub (pinned to 5e758547a8)