phalcon/cphalcon · error · ConflictTargetColumnRequired
ON CONFLICT requires at least one conflict-target column
Error message
ON CONFLICT requires at least one conflict-target column
What it means
Dialect::onConflictUpdate() appends an `ON CONFLICT (col, ...) DO UPDATE SET ...` upsert clause to an INSERT statement. The conflict target - the column list after ON CONFLICT - is what the database matches against a unique index/constraint, so an empty conflictColumns array throws ConflictTargetColumnRequired before any SQL is built.
Source
Thrown at phalcon/Db/Dialect.zep:549
public function refreshMaterializedView( string viewName, string schemaName = null, bool concurrent = false) -> string
{
throw new MaterializedViewsNotSupported();
}
/**
* Appends an `ON CONFLICT (col, ...) DO UPDATE SET col = excluded.col`
* upsert clause to the supplied INSERT statement. The syntax is the
* SQL standard form recognized by PostgreSQL (9.5+) and SQLite (3.24+).
* MySQL overrides this method to throw because its `ON DUPLICATE KEY
* UPDATE` has a different shape (deferred to parser item #23).
*/
public function onConflictUpdate( string sqlQuery, array conflictColumns, array updateColumns) -> string
{
var col;
array assignments;
if unlikely empty conflictColumns {
throw new ConflictTargetColumnRequired();
}
if unlikely empty updateColumns {
throw new ConflictUpdateColumnRequired();
}
let assignments = [];
for col in updateColumns {
let assignments[] = this->escape((string) col)
. " = excluded." . this->escape((string) col);
}
return sqlQuery
. " ON CONFLICT (" . this->getColumnList(conflictColumns) . ")"
. " DO UPDATE SET " . implode(", ", assignments);
}
/**View on GitHub (pinned to b7419de9cd)
Solutions
- Pass the conflict-target column(s): typically the primary key or a unique-index column, e.g. ['id'] or ['sku'].
- Ensure the target columns match a real unique index or primary key on the table, or PostgreSQL/SQLite will reject the statement.
- Validate count($conflictColumns) > 0 in your upsert helper and fail with an application-level message.
Example fix
// before $sql = $dialect->onConflictUpdate($insertSql, [], ['qty = excluded.qty']); // throws ConflictTargetColumnRequired // after $sql = $dialect->onConflictUpdate($insertSql, ['sku'], ['qty']);
Defensive patterns
Strategy: validation
Validate before calling
if (count($conflictColumns) === 0) {
throw new InvalidArgumentException('ON CONFLICT requires a conflict-target column');
}
$sql = $dialect->onConflictUpdate($insertSql, $conflictColumns, $updateColumns); Type guard
function hasConflictTarget(array $conflictColumns): bool
{
return $conflictColumns !== []
&& array_filter($conflictColumns, 'is_string') !== [];
} Prevention
- Always name the conflict target explicitly - usually the primary key or a unique-index column.
- Verify a matching unique index/constraint exists before generating the upsert.
- Keep conflict-target and update-column lists in one config object so they cannot be swapped.
When it happens
Trigger: Calling $dialect->onConflictUpdate($insertSql, [], ['qty']) with an empty conflict-target array; building conflict columns dynamically from a unique-index lookup that returned nothing; passing the update columns in the wrong argument position.
Common situations: Upsert helpers where the conflict key list comes from config that can be empty; forgetting that the target must reference an existing UNIQUE index/PK; argument-order mixups between conflictColumns and updateColumns.
Related errors
- ON CONFLICT DO UPDATE requires at least one update column
- Materialized views are not supported by this dialect
- RETURNING clauses are not supported by this dialect
- The table must contain at least one column
- The database must be specified with either 'dbname' or 'dsn'
AI-assisted analysis of phalcon/cphalcon@b7419de9cd (2026-08-21).
Data as JSON: /api/errors/f1939163a1b8e7b5.
Report an issue: GitHub.