laravel/framework · error · RuntimeException
This database engine does not support upserts.
Error message
This database engine does not support upserts.
What it means
The base Grammar's compileUpsert throws by default. All four major engine grammars (MySqlGrammar, PostgresGrammar, SQLiteGrammar, SqlServerGrammar) override it with engine-specific syntax (INSERT ... ON DUPLICATE KEY UPDATE / ON CONFLICT DO UPDATE / INSERT ON CONFLICT DO UPDATE / MERGE). This error fires only for a custom grammar extending the base Grammar without an override.
Solutions
- Switch to a built-in connection (mysql, pgsql, sqlite, or sqlsrv) — all four override compileUpsert
- Override compileUpsert in your custom grammar with the correct SQL for your engine
- Replace upsert() with a try/catch around insert() followed by update(), or use a raw statement with your engine's native upsert syntax
Example fix
// before — custom grammar without upsert support
DB::table('users')->upsert(['email' => 'a@b.com', 'name' => 'Alice'], ['email'], ['name']);
// after — manual insert-or-update fallback
$exists = DB::table('users')->where('email', 'a@b.com')->exists();
if ($exists) {
DB::table('users')->where('email', 'a@b.com')->update(['name' => 'Alice']);
} else {
DB::table('users')->insert(['email' => 'a@b.com', 'name' => 'Alice']);
} Defensive patterns
Strategy: try-catch
Validate before calling
$grammar = DB::connection()->getQueryGrammar();
$method = new ReflectionMethod($grammar, 'compileUpsert');
if ($method->getDeclaringClass()->getName() !== 'Illuminate\\Database\\Query\\Grammars\\Grammar') {
DB::table('users')->upsert($values, ['email'], ['name']);
} Type guard
function grammarSupportsUpsert(): bool {
$grammar = DB::connection()->getQueryGrammar();
$method = new ReflectionMethod($grammar, 'compileUpsert');
return $method->getDeclaringClass()->getName() !== 'Illuminate\\Database\\Query\\Grammars\\Grammar';
} Try / catch
try {
DB::table('users')->upsert($values, ['email'], ['name']);
} catch (\RuntimeException $e) {
if (str_contains($e->getMessage(), 'upserts')) {
// manual fallback: check existence then insert or update
foreach ($values as $row) {
$exists = DB::table('users')->where('email', $row['email'])->exists();
$exists
? DB::table('users')->where('email', $row['email'])->update($row)
: DB::table('users')->insert($row);
}
} else {
throw $e;
}
} Prevention
- Use a built-in connection — all four override compileUpsert
- If using a custom grammar, override compileUpsert before calling upsert()
- Keep a manual insert-or-update fallback ready for custom drivers
When it happens
Trigger: Using upsert() on a query builder whose grammar is a custom class extending Grammar without implementing compileUpsert. This occurs with third-party or community database drivers that lack upsert support.
Common situations: Using a community database package (e.g., a ClickHouse, DynamoDB, or Cassandra driver) that extends the base Grammar but has not implemented upsert operations.
Related errors
- This database engine does not support JSON contains…
- This database engine does not support JSON contains key…
- This database engine does not support JSON length…
- The unique columns must not be empty.
- This database engine does not support inserting while…
AI-assisted analysis of laravel/framework@e0f6eb3518 (2026-08-11).
Data as JSON: /api/errors/74068b23795d943e.
Report an issue: GitHub.
Appendix: source
Thrown at src/Illuminate/Database/Query/Grammars/Grammar.php:1420
$joins = $this->compileJoins($query, $query->joins);
return "update {$table} {$joins} set {$columns} {$where}";
}
/**
* Compile an "upsert" statement into SQL.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $values
* @param array $uniqueBy
* @param array $update
* @return string
*
* @throws \RuntimeException
*/
public function compileUpsert(Builder $query, array $values, array $uniqueBy, array $update)
{
throw new RuntimeException('This database engine does not support upserts.');
}
/**
* Prepare the bindings for an update statement.
*
* @param array $bindings
* @param array $values
* @return array
*/
public function prepareBindingsForUpdate(array $bindings, array $values)
{
$cleanBindings = Arr::except($bindings, ['select', 'join']);
$values = Arr::flatten(array_map(fn ($value) => value($value), $values));
return array_values(
array_merge($bindings['join'], $values, Arr::flatten($cleanBindings))
);View on GitHub (pinned to e0f6eb3518)