A fatal error occurs when extensions make AJAX requests on Joomla 5.x with PHP 8.2+:
Fatal error: Uncaught Error: mysqli object is already closed
in libraries/vendor/joomla/database/src/Mysqli/MysqliDriver.php on line 318
The error occurs because PHP 8 throws Error objects (not Exception) when calling methods on a closed mysqli connection. The current code doesn't catch these errors.
AJAX requests should complete successfully without fatal errors.
Fatal error is thrown in MysqliDriver.php at line 318 during the disconnect() method when mysqli->close() is called on an already-closed connection.
Full error message:
Fatal error: Uncaught Error: mysqli object is already closed
in /libraries/vendor/joomla/database/src/Mysqli/MysqliDriver.php:318
Stack trace:
#0 /libraries/vendor/joomla/database/src/Mysqli/MysqliDriver.php(318): mysqli->close()
#1 /libraries/vendor/joomla/database/src/DatabaseDriver.php(496): Joomla\Database\Mysqli\MysqliDriver->disconnect()
#2 [internal function]: Joomla\Database\DatabaseDriver->__destruct()
#3 {main}
thrown in /libraries/vendor/joomla/database/src/Mysqli/MysqliDriver.php on line 318
| Component | Version |
|---|---|
| Joomla CMS | 5.4.x (also affects 5.2.x or 5.3.x) |
| PHP | 8.2.29 |
| MySQL | 8.x |
| Hosting | Cloudways (but not hosting-specific) |
| Browser | All browsers (server-side error) |
Modify MysqliDriver.php to catch \Throwable instead of just \Exception.
libraries/vendor/joomla/database/src/Mysqli/MysqliDriver.php
Current code:
public function connected()
{
if (\is_object($this->connection)) {
return $this->connection->stat() !== false;
}
return false;
}Fixed code:
public function connected()
{
if (\is_object($this->connection)) {
try {
return $this->connection->stat() !== false;
} catch (\Throwable $e) {
return false;
}
}
return false;
}Current code:
public function disconnect()
{
// Close the connection.
if (\is_callable([$this->connection, 'close'])) {
$this->connection->close();
}
parent::disconnect();
}Fixed code:
public function disconnect()
{
// Close the connection.
if (\is_callable([$this->connection, 'close'])) {
try {
@$this->connection->close();
} catch (\Throwable $e) {
// Connection already closed, ignore
}
}
parent::disconnect();
}In PHP 8, when you call a method on a closed mysqli object, it throws an Error (not an Exception).
The \Throwable interface is the base interface for both Error and Exception in PHP 7+, so catching \Throwable handles both cases.
PHP Exception Hierarchy:
Throwable
├── Error (PHP 7+)
│ ├── TypeError
│ ├── ArgumentCountError
│ └── ... (other Error types)
└── Exception
├── RuntimeException
└── ... (other Exception types)
This fix has been tested and confirmed working:
| Source | Link |
|---|---|
| Similar fix in joomlatools-framework | joomlatools/joomlatools-framework#563 |
| Joomla Forum report (5.3.0) | https://forum.joomla.org/viewtopic.php?f=841&t=1015711 |
| Joomla Forum report (general) | https://forum.joomla.org/viewtopic.php?t=1005416 |
| Joomla Forum report (HTTP 500) | https://forum.joomla.org/viewtopic.php?t=1005202 |
wait_timeout settings do not resolve this issue (tested with values up to 900 seconds)High - This is a breaking issue that affects core functionality on the recommended PHP version (8.2+).
| Labels |
Removed:
?
|
||
| Labels |
Added:
No Code Attached Yet
|
||
The file you list to modify is incorrect as that (2.0) is not the version used in current releases of joomla
THANKS.
I changed the name of the "file to modify": https://github.com/joomla-framework/database/blob/4.x-dev/src/Mysqli/MysqliDriver.php
I hope this is the right one... I'm not a developer and don't know github.
Claude is my friend.
A fatal error occurs when extensions make AJAX requests on Joomla 5.x with PHP 8.2+:
Please describe, doing what exactly?
Fatal error: Uncaught Error: mysqli object is already closed
To get this you should do something really wrong
Thank you for your response. Let me clarify with more technical details.
The error occurs when:
task=experiences.filter)__destruct() method in DatabaseDriver which calls disconnect()In PHP 7.x, calling mysqli->close() on an already-closed connection would fail silently or return false.
In PHP 8.0+, this throws an Error object (not an Exception):
Error: mysqli object is already closed
The current code in MysqliDriver.php doesn't catch Error objects - only Exception. But in PHP's exception hierarchy:
Throwable
├── Error (thrown by mysqli in PHP 8)
└── Exception (what current code catches)
Fatal error: Uncaught Error: mysqli object is already closed
in libraries/vendor/joomla/database/src/Mysqli/MysqliDriver.php on line 318
Modify MysqliDriver.php to catch \Throwable instead of nothing:
disconnect() method:
public function disconnect()
{
if (\is_callable([$this->connection, 'close'])) {
try {
@$this->connection->close();
} catch (\Throwable $e) {
// Connection already closed, ignore
}
}
parent::disconnect();
}connected() method:
public function connected()
{
if (\is_object($this->connection)) {
try {
return $this->connection->stat() !== false;
} catch (\Throwable $e) {
return false;
}
}
return false;
}The same fix was applied to joomlatools-framework: joomlatools/joomlatools-framework#563
I have tested this fix on Joomla 5.4.1 with PHP 8.2.29 - the AJAX requests work correctly after the modification, with no side effects on normal database operations.
This is not about "doing something wrong" - it's a defensive coding practice needed for PHP 8 compatibility. The connection being closed before the destructor runs is a valid edge case that PHP 8 handles differently than PHP 7.
Please contact Developers of mod_sr_experience_filter and com_solidares to fix their extensions.
Thanks.
From what I understood from your screenshot they say something about hosting problem.
But without any detail.
Well, to me it is clearly not Joomla bug.
You can try ask for help on forum.joomla.org or ask for more help from the developers to track the root cause of the issue (especial if it paid extension).
@Fedik beside that broke AI slop we might should check if we are connected before we close the connection. Shouldn't cost too much performance. It
Beside that @kristof33 please contact the extension provider or debug it your self and find out where the database is closed the first time, you can add debug_print_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); die(); to the close method.
What I dont understand is how solidres says it (now) requires Joomla 5 and yet fails with an error in a core Joomla 5 library. That doesnt make any sense to me. If there is an error in a core Joomla 5 library then logic says that everyone using solidres would have the same problem
Thank you for your response.
First, I apologize for using AI to help me write these reports - I'm not a developer. But without AI assistance, I wouldn't be here trying to help solve this issue at all. I hope you can understand.
As requested by @HLeithner, I added debug_print_backtrace() to the disconnect() method. Here are the results:
=== [2025-12-27 21:24:13] MysqliDriver::disconnect() called ===
#0 /home/950585.cloudwaysapps.com/xqsmmcgzgg/public_html/libraries/vendor/joomla/session/src/Handler/DatabaseHandler.php(86): Joomla\Database\Mysqli\MysqliDriver->disconnect()
#1 [internal]: Joomla\Session\Handler\DatabaseHandler->close()
#2 /home/950585.cloudwaysapps.com/xqsmmcgzgg/public_html/libraries/vendor/joomla/session/src/Storage/NativeStorage.php(114): session_write_close()
#3 /home/950585.cloudwaysapps.com/xqsmmcgzgg/public_html/libraries/src/Session/Storage/JoomlaStorage.php(148): Joomla\Session\Storage\NativeStorage->close()
#4 [internal]: Joomla\CMS\Session\Storage\JoomlaStorage->close()
=== [2025-12-27 21:24:13] MysqliDriver::disconnect() called ===
#0 /home/950585.cloudwaysapps.com/xqsmmcgzgg/public_html/libraries/vendor/joomla/database/src/DatabaseDriver.php(496): Joomla\Database\Mysqli\MysqliDriver->disconnect()
#1 [internal]: Joomla\Database\DatabaseDriver->__destruct()
=== [2025-12-27 21:24:13] MysqliDriver::disconnect() called ===
#0 /home/950585.cloudwaysapps.com/xqsmmcgzgg/public_html/libraries/vendor/joomla/database/src/DatabaseDriver.php(496): Joomla\Database\Mysqli\MysqliDriver->disconnect()
#1 [internal]: Joomla\Database\DatabaseDriver->__destruct()
=== CAUGHT ERROR: mysqli object is already closed ===
=== [2025-12-27 21:24:47] MysqliDriver::disconnect() called ===
#0 /home/950585.cloudwaysapps.com/xqsmmcgzgg/public_html/libraries/vendor/joomla/session/src/Handler/DatabaseHandler.php(86): Joomla\Database\Mysqli\MysqliDriver->disconnect()
#1 [internal]: Joomla\Session\Handler\DatabaseHandler->close()
#2 /home/950585.cloudwaysapps.com/xqsmmcgzgg/public_html/libraries/vendor/joomla/session/src/Storage/NativeStorage.php(114): session_write_close()
#3 /home/950585.cloudwaysapps.com/xqsmmcgzgg/public_html/libraries/src/Session/Storage/JoomlaStorage.php(148): Joomla\Session\Storage\NativeStorage->close()
#4 [internal]: Joomla\CMS\Session\Storage\JoomlaStorage->close()
=== [2025-12-27 21:24:47] MysqliDriver::disconnect() called ===
#0 /home/950585.cloudwaysapps.com/xqsmmcgzgg/public_html/libraries/vendor/joomla/database/src/DatabaseDriver.php(496): Joomla\Database\Mysqli\MysqliDriver->disconnect()
#1 [internal]: Joomla\Database\DatabaseDriver->__destruct()
=== [2025-12-27 21:24:47] MysqliDriver::disconnect() called ===
#0 /home/950585.cloudwaysapps.com/xqsmmcgzgg/public_html/libraries/vendor/joomla/database/src/DatabaseDriver.php(496): Joomla\Database\Mysqli\MysqliDriver->disconnect()
#1 [internal]: Joomla\Database\DatabaseDriver->__destruct()
=== CAUGHT ERROR: mysqli object is already closed ===
=== [2025-12-27 21:24:48] MysqliDriver::disconnect() called ===
#0 /home/950585.cloudwaysapps.com/xqsmmcgzgg/public_html/libraries/vendor/joomla/session/src/Handler/DatabaseHandler.php(86): Joomla\Database\Mysqli\MysqliDriver->disconnect()
#1 [internal]: Joomla\Session\Handler\DatabaseHandler->close()
#2 /home/950585.cloudwaysapps.com/xqsmmcgzgg/public_html/libraries/vendor/joomla/session/src/Storage/NativeStorage.php(114): session_write_close()
#3 /home/950585.cloudwaysapps.com/xqsmmcgzgg/public_html/libraries/src/Session/Storage/JoomlaStorage.php(148): Joomla\Session\Storage\NativeStorage->close()
#4 [internal]: Joomla\CMS\Session\Storage\JoomlaStorage->close()
=== [2025-12-27 21:24:48] MysqliDriver::disconnect() called ===
#0 /home/950585.cloudwaysapps.com/xqsmmcgzgg/public_html/libraries/vendor/joomla/database/src/DatabaseDriver.php(496): Joomla\Database\Mysqli\MysqliDriver->disconnect()
#1 [internal]: Joomla\Database\DatabaseDriver->__destruct()
=== [2025-12-27 21:24:48] MysqliDriver::disconnect() called ===
#0 /home/950585.cloudwaysapps.com/xqsmmcgzgg/public_html/libraries/vendor/joomla/database/src/DatabaseDriver.php(496): Joomla\Database\Mysqli\MysqliDriver->disconnect()
#1 [internal]: Joomla\Database\DatabaseDriver->__destruct()
=== CAUGHT ERROR: mysqli object is already closed ===
The backtrace shows the sequence of events for each AJAX request:
DatabaseHandler.php(86) calls disconnect() during session_write_close() - the connection is closed hereDatabaseDriver.php(496) via __destruct() calls disconnect() again__destruct() tries to close - CAUGHT ERROR: mysqli object is already closedAll files involved are Joomla core:
libraries/vendor/joomla/session/src/Handler/DatabaseHandler.phplibraries/vendor/joomla/session/src/Storage/NativeStorage.phplibraries/src/Session/Storage/JoomlaStorage.phplibraries/vendor/joomla/database/src/DatabaseDriver.phpThe extension simply makes an AJAX request. The multiple disconnect() calls are made by Joomla's own session and database classes.
The backtrace confirms that the issue comes from Joomla's own classes calling disconnect() multiple times. The fix I proposed earlier (catching \Throwable) works and has been tested on my staging site with Joomla 5.4.1 and PHP 8.2.29.
I hope this debug information helps. Thank you for your time.
if possible please send me credentials and url to harald.leithner@community.joomla.org and I will take a look.
thanks, the website is protected by a basic-auth, could you please send me the password for this too?
Hello,
All login/pass is in the mail (basic-auth and joomla)
Thanks for your time and attention,
Best regards,
Doesn't work
I have sent a new mail.
Best regards,
Thanks, I checked it but can't replicated that, maybe you can show me which url I have to open...
btw. you are using falang which replaces/extend the joomla database layer, which is not shown in the stacktrace which is strange.
I restored the MysqliDriver.php file without patching (original file).
You can go to https://phpstack-950585-6089052.cloudwaysapps.com/en/booking
Then click on 1 filter in the left menu (eg: Visit Bordeaux) to observe the logs in Chrome Inspector (Joomla Debug mode also does not work correctly without the previous fix)
There is a more simpler way to check: use a different hosting, it could be your local server or something else, then try to replicate this issue. Disabling Falang is also a step that you should take.
Also, your site homepage has a huge "mysqli object is already closed" error in the footer:
https://phpstack-950585-6089052.cloudwaysapps.com/en/
Therefore I believe it is more likely a server issue than a Joomla core or extension issues
| Status | New | ⇒ | Closed |
| Closed_Date | 0000-00-00 00:00:00 | ⇒ | 2026-01-01 16:39:46 |
| Closed_By | ⇒ | HLeithner |
I checked the page again and disabled the "System - FaLang Database Driver", which resolves the issue, please contact Stéphane if the error still exists after upgrading falang to the latest version.
I'm closing this issue for now.
The file you list to modify is incorrect as that (2.0) is not the version used in current releases of joomla