-
Notifications
You must be signed in to change notification settings - Fork 11.6k
Description
Laravel Version
12.33.0
PHP Version
8.3.19
Database Driver & Version
SQL Server - pdo_sqlsrv v5.12.0
Description
The Eloquent update()
method is meant to support subqueries. However, this only works for MySQL and MariaDB. For other databases, trying to use update()
with subqueries results in an error while the query is being prepared:
Object of class Closure could not be converted to string
Click to expand detailed error info
Relevant part of stack trace
[stacktrace]
#0 /var/www/app/vendor/laravel/framework/src/Illuminate/Database/Connection.php(718): PDOStatement->bindValue()
#1 /var/www/app/vendor/laravel/framework/src/Illuminate/Database/Connection.php(593): Illuminate\\Database\\Connection->bindValues()
#2 /var/www/app/vendor/laravel/framework/src/Illuminate/Database/Connection.php(811): Illuminate\\Database\\Connection->Illuminate\\Database\\{closure}()
#3 /var/www/app/vendor/laravel/framework/src/Illuminate/Database/Connection.php(778): Illuminate\\Database\\Connection->runQueryCallback()
#4 /var/www/app/vendor/laravel/framework/src/Illuminate/Database/Connection.php(583): Illuminate\\Database\\Connection->run()
#5 /var/www/app/vendor/laravel/framework/src/Illuminate/Database/Connection.php(535): Illuminate\\Database\\Connection->affectingStatement()
#6 /var/www/app/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php(3917): Illuminate\\Database\\Connection->update()
Full error message
[2025-10-13 16:25:47] local.ERROR: Object of class Closure could not be converted to string {"exception":"[object] (Error(code: 0): Object of class Closure could not be converted to string at /var/www/app/vendor/laravel/framework/src/Illuminate/Database/Connection.php:718)
Pretty error message
Note: Codebase-specific info was pixelated

Code details
This functionality was added in PR #53254.
The bug is introduced within the same PR, in commit 7b2d56b. For unexplained reasons, in case of subquery update values, the $bindings
values are wrapped into a closure. The method Grammar::prepareBindingsForUpdate()
is updated to execute closure values, binding the return value to the query instead.
However, most overrides of Grammar::prepareBindingsForUpdate()
don't use the original at all, and they were also not directly modified to support closures:
SQLiteGrammar::prepareBindingsForUpdate()
PostgresGrammar::prepareBindingsForUpdate()
SqlServerGrammar::prepareBindingsForUpdate()
Steps To Reproduce
- Configure Laravel to use a database driver other than MySQL/MariaDB
- Note: I have personally only verified this bug against SQL Server
- Run
php artisan tinker
in a shell - Input and run this script:
DB::table('fake_table') ->update([ 'fake_column' => DB::table('fake_source_table')->selectRaw('fake_source_column'), ]);
- Observe the error
Error Object of class Closure could not be converted to string.
References
Original issue, closed without resolution: