phalcon/cphalcon · error · Phalcon\Db\Exceptions\ReturningRequiresColumn

RETURNING requires at least one column or '*'

Error message

RETURNING requires at least one column or '*'

What it means

Phalcon\Db\Dialect\Sqlite::returning() appends a RETURNING clause (SQLite 3.35+) to an INSERT/UPDATE/DELETE statement and requires at least one column name or '*'. An empty array throws ReturningRequiresColumn because a bare RETURNING keyword is not valid SQL.

Source

Thrown at phalcon/Db/Dialect/Sqlite.zep:669

    /**
     * Generates SQL to modify a column in a table
     */
    public function modifyColumn( string tableName,  string schemaName, <ColumnInterface> column, <ColumnInterface> currentColumn = null) -> string
    {
        throw new SqliteAlterColumnNotSupported();
    }

    /**
     * Appends a `RETURNING` clause to the supplied INSERT/UPDATE/DELETE
     * statement. Supported by SQLite 3.35+. Pass `["*"]` for `RETURNING *`,
     * or a list of column names.
     */
    public function returning( string sqlQuery,  array columns) -> string
    {
        var first;

        if unlikely empty columns {
            throw new ReturningRequiresColumn();
        }

        if count(columns) == 1 {
            let first = (string) columns[0];

            if first == "*" {
                return sqlQuery . " RETURNING *";
            }
        }

        return sqlQuery . " RETURNING " . this->getColumnList(columns);
    }

    /**
     * SQLite cannot modify existing columns or add/drop foreign keys, primary
     * keys, or check constraints through `ALTER TABLE`; those operations throw
     * a dedicated `Sqlite*NotSupported` exception.
     */

View on GitHub (pinned to b7419de9cd)

Solutions

  1. Pass ['*'] when all columns are wanted: $dialect->returning($sql, ['*'])
  2. Guard the call: only invoke returning() when count($columns) > 0
  3. In your wrapper, normalize null/[] to ['*'] or skip the clause entirely

Example fix

// before
$sql = $dialect->returning($insert, $options['returning'] ?? []);

// after
$cols = $options['returning'] ?? null;
$sql  = empty($cols) ? $insert : $dialect->returning($insert, $cols);
Defensive patterns

Strategy: validation

Validate before calling

$cols = $columns ?? [];
if ([] !== $cols) {
    $sql = $dialect->returning($sql, $cols);
}
// or, when the caller always wants values back: $dialect->returning($sql, ['*'])

Try / catch

try {
    $sql = $dialect->returning($insert, $columns);
} catch (\Phalcon\Db\Exceptions\ReturningRequiresColumn $e) {
    $sql = $dialect->returning($insert, ['*']);
}

Prevention

When it happens

Trigger: Forwarding an optional list that defaulted to []: $dialect->returning($insert, $options['returning'] ?? []); wrappers that translate 'no columns selected' into an empty array; refactors that turned a null default into [].

Common situations: Optional RETURNING support behind a feature flag; query-builder wrappers that pass through caller-supplied column lists unchecked; code ported from dialects where the empty case was tolerated.

Related errors


AI-assisted analysis of phalcon/cphalcon@b7419de9cd (2026-08-21). Data as JSON: /api/errors/3543d179255a589c. Report an issue: GitHub.