read 4 min
2 / 6
Apr 12

All,

OS: Archlinux PHP: 8.2.28 Apache: 2.4.63 MongoDB: 4.4.29 Composer Runtime: 2.0 MongoDB Driver: updated 4/12/2025

I have several stable PHP interfaces to mongodb that suddenly stopped working on update of php-mongodb from Ver. 1.21.0 to 2.0.0. The error is:

[Sat Apr 12 01:25:20.286158 2025] [php:error] [pid 685:tid 685] [client 192.168.6.224:53078] PHP Fatal error: Declaration of MongoDB\\Model\\BSONArray::bsonSerialize() must be compatible with MongoDB\\BSON\\Serializable::bsonSerialize(): stdClass|MongoDB\\BSON\\Document|MongoDB\\BSON\\PackedArray|array in /srv/http/vendor/mongodb/mongodb/src/Model/BSONArray.php on line 74, referer: https://2pi.3111skyline.com/tmp/db/jnl-grid/

Was there a change in the API from Ver 1.21.0 to 2.0.0 of the library that broke backwards compatibility or is this a bug?

The interface worked fine with all versions of php-mongodb from 1.15.3 through 1.21.0, but immediately broke with the error above on update to version 2.0.0.

If I can provide more information, please don’t hesitate to ask.

read 4 min

All, the problem was composer. The error message you see above is what occurs when you have the driver that supports through version 1.21 when the php-mongo library has been updated to 2.0.0.

Apparently what happened is when composer was run to update the driver files, the new driver files were installed one directory level below the current driver files leaving the current files in place and placing the new driver files in a new vendor directory below the current, e.g. the correct driver location is: /srv/http/vendor/mongodb/mongodb however after the update, those files were untouched, and then new driver files ended up on /srv/http/vendor/vendor/mongodb/mongodb.

After moving the files in /srv/http/vendor/vendor up one level removing the duplicate vendor directory, updating to the php-mongodb-2.0.0 library and reloading the web server, all was again right in the world of mongo and PHP.

It just took a while to discover the issue, and at that point the post was already pending() with no way to remove it.

Sorry for the noise, but if anyone else has the same .../BSONArray.php on line 74, there is a good chance it is the driver files and composer at fault. (another good reason to package all files and not rely on 3rd party web-installers…

Was there a change in the API from Ver 1.21.0 to 2.0.0 of the library that broke backwards compatibility or is this a bug?

Yes, which is why we released these changes as 2.0.0 as opposed to 1.22.0. More specifically, the previous tentative return types were changed to be definitive, which is a BC break and hence only done in 2.0.0.

The issue that you ran into isn’t with composer, but rather with PECL. When you run pecl install mongodb, PECL will pick the latest release to install, which as of this writing is 2.0.0. This means that you’re using the new driver with the old library version, which isn’t compatible. Depending on where you run composer install or composer update and how you deploy the files, composer doesn’t have a chance of catching the error. For example, if you run composer update on a system with ext-mongodb 1.21 installed, composer will pick version 1.21 of the library. If you have ext-mongodb 2.0 installed, composer will pick version 2.0 of the library. So, if you copy the files to your server but have a different extension version installed, things will be broken, which is what I suspect happened here.

I don’t know how you managed to get nested vendor directories, so I can’t comment on that.

another good reason to package all files and not rely on 3rd party web-installers

That won’t do you any good here, as the issue wasn’t composer, but pecl. The PHP Foundation is currently leading an effort to replace PECL with a tool called pie built on top of composer, which will allow more flexibility when choosing extension versions to install. If you use PECL, you’ll have to specify an exact version to install:

pecl install mongodb-1.21.0 pecl install mongodb-2.0.0

Without the exact version, you can’t be sure which version will be installed and it will depend on timing. Going forward, we will upload 1.x releases first, followed by 2.x releases, so that the latest version will always be a 2.x version, but there will be a short window where PECL could install a 1.x release just before we upload a 2.x release. On the other hand, if you use pie, you can use version constraints like in composer.json:

php pie.phar install mongodb/mongodb-extension:^1.21 php pie.phar install mongodb/mongodb-extension:^2.0

The advantage is that you don’t have to update your provisioning scripts every time a new version is released, but you will receive backward compatible updates automatically. Please be aware that pie is still in active development and may contain bugs. We have tested the driver installation and it works so far, but changes in pie could result in short-term breakage.

Last but not least, we follow Semantic Versioning for our driver releases, so we won’t release a 2.1 version of the driver that requires you to make changes in order to continue working correctly. A 3.0 release however will once again contain BC breaks. That said, we currently don’t have any plans for a 3.0 release with breaking changes. You can also continue using 1.21, as we’ll be providing bug fixes for the 1.x release line for another year before this version becomes end-of-life and we only support 2.x releases.

Thank you Andreas,

Yes, I generally understand semantic versioning, and major-version updates coming with API breaks. What made it the challenge was the SNAFU with the additional vendor/vendor directory going unnoticed for a time and wondering why the update of both the driver and library hadn’t played nicely together.

It’s the proverbial 3-legged stool, with the database, the driver and the PHP library all being separate legs of the stool. In this case the PHP library is packaged by Archlinux rather than being a manual pecl install. The driver being composer, and eventually pie as you indicate.

The primary concern with the 3rd web-installers isn’t difficulty with ensuring the proper version, but concern over supply-chain compromise. Between the recent and repeated PyPi and npm compromises, you add github to the list and “confidence” in secure delivery for a server interface is a big concern. That could be alleviated by simply providing a direct download of the driver package in archive format. At least in my case the driver file size is trivial, less than 2M total installed.

Thank you for your detailed and thorough explanation!

David, I appreciate your concern regarding supply chain security. While there is still a lot of work to do, there are some steps we have taken at MongoDB to help users protect themselves.

Just to clarify some naming confusion, the PHP driver for MongoDB consists of two parts, the mongodb extension (typically installed via PECL, in your case through Archlinux) and the library, which is typically installed using composer using metadata hosted on packagist.org.

When looking at supply chain security, we have to treat the extension and library separately due to the two completely different installation mechanisms. What both have in common is that GitHub is the canonical source for all releases. This is because as part of our secure software development lifecycle program at MongoDB, we have taken several steps to protect the integrity of the code:

  • Code can not be pushed to branches directly, but have to be reviewed in a pull request to be mergeable
  • Releases can only be done through an automation with credentials that are not accessible to MongoDB employees
  • Tags on GitHub are signed using a PGP key
  • For the extension, we provide a PECL archive along with a signature for each release

After a release, we upload this PECL archive to https://pecl.php.net/mongodb so that it becomes installable using the pecl binary. Packages provided by Linux distributions are not within our control, and you have to trust the packager to not compromise the integrity of the package.
An alternative is manually fetching the file from a GitHub release and verifying it against the signature we attach to that same release. We have documented these steps in the Release Integrity section of the README. We also plan to add GitHub attestation to the release process to give more options for verifying release integrity.

When it comes to the library, the difference to the driver is that we don’t provide a separate archive with a generated signature, as we completely rely on composer to install our packages. Composer metadata is automatically updated through GitHub, and when downloading code through composer by default the archive of the corresponding tag is downloaded. In this case, you’re trusting GitHub to serve up the correct code for a tag. Note that there are no integrity checks added here, as the archives provided by GitHub are generated dynamically and thus do not have the same signature over time.

This brings us to the new pie installer for extensions. This builds on the packagist.org ecosystem, so everything works the same as for composer packages. The only difference is that we instruct pie to download the archive attached to a release as opposed to fetching the archive automatically generated by GitHub. The main reason for this is technical, but it comes with the benefit of potentially adding signature verification in the future.

I hope this gives you a bit more background on how we try to preserve release integrity and keep your supply chain secure, but please follow up if you have any more questions.

Closed on Apr 20

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.