Environment
Gravity PDF: 6.14.2 (also reproduced on 6.13.5)
WP-Stateless: 4.4.1 (bundles Monolog 3.x + PSR/Log v3)
WordPress: latest
PHP: 8.3.26
Error
Fatal error: Declaration of Monolog\Logger::emergency(Stringable|string $message, array $context = []): void must be compatible with GFPDF_Vendor\Psr\Log\LoggerInterface::emergency($message, array $context = []) in /wp-content/plugins/wp-stateless/lib/Google/vendor/monolog/monolog/src/Monolog/Logger.php on line 683
Reproduction
Install Gravity PDF 6.14.2 + WP-Stateless 4.4.1 (or any plugin shipping Monolog 3 / PSR/Log v3).
Trigger any code path that boots WP-Stateless's Google client (image upload, GCS sync, cron). This lazy-loads wp-stateless/lib/Google/vendor/autoload.php.
Backend fatals.
Root cause
Gravity PDF's PSR/Log compatibility shim in src/Helper/Log/Logger.php::get_monolog() decides the PSR/Log version at first call by running trait_exists('\Psr\Log\LoggerTrait'). WP-Stateless registers its v3 Psr\Log\ autoloader lazily (only when the Google client is instantiated), so on first call from Gravity PDF the trait isn't registered yet → shim falls into the v1 branch and runs:
class_alias( '\GFPDF_Vendor\Psr\Log\LoggerInterface', '\Psr\Log\LoggerInterface' );
This permanently binds the global \Psr\Log\LoggerInterface to the v1 signature. Later, when WP-Stateless boots its bundled Monolog 3, PHP rejects Monolog\Logger::emergency(string|\Stringable $message): void against the aliased v1 signature.
A second, structural issue: in vendor_prefixed/monolog/src/Monolog/Logger.php (and ~28 other files inside vendor_prefixed/), the \Psr\Log\ namespace was not prefixed by the build tool, e.g.:
class Logger implements \Psr\Log\LoggerInterface, \GFPDF_Vendor\Monolog\ResettableInterface
So Gravity PDF's own prefixed Monolog still depends on the global \Psr\Log\LoggerInterface resolving to v1, which is why vendor/psr/log/ still ships an unprefixed v1 alongside vendor_prefixed/psr/log/.
The result is that class_alias is needed every time another plugin loads PSR/Log v3 lazily after Gravity PDF has booted — and the compat shim's trait_exists check is a race against lazy autoloaders.
Suggested fix (one or more)
Replace trait_exists snapshot with an autoload-aware probe, or defer get_monolog() until plugins_loaded priority near PHP_INT_MAX so lazy autoloaders have registered.
Prefix every \Psr\Log\… reference inside vendor_prefixed/ so Gravity PDF's prefixed Monolog implements \GFPDF_Vendor\Psr\Log\LoggerInterface. Then drop the unprefixed vendor/psr/log/ ship and the global class_alias entirely.
Provide a filter or constant (e.g. GFPDF_FORCE_PSR_LOG_VERSION) so site owners can pin the target version when load-order detection is unreliable.
Environment
Gravity PDF: 6.14.2 (also reproduced on 6.13.5)
WP-Stateless: 4.4.1 (bundles Monolog 3.x + PSR/Log v3)
WordPress: latest
PHP: 8.3.26
Error
Fatal error: Declaration of Monolog\Logger::emergency(Stringable|string $message, array $context = []): void must be compatible with GFPDF_Vendor\Psr\Log\LoggerInterface::emergency($message, array $context = []) in /wp-content/plugins/wp-stateless/lib/Google/vendor/monolog/monolog/src/Monolog/Logger.php on line 683
Reproduction
Install Gravity PDF 6.14.2 + WP-Stateless 4.4.1 (or any plugin shipping Monolog 3 / PSR/Log v3).
Trigger any code path that boots WP-Stateless's Google client (image upload, GCS sync, cron). This lazy-loads wp-stateless/lib/Google/vendor/autoload.php.
Backend fatals.
Root cause
Gravity PDF's PSR/Log compatibility shim in src/Helper/Log/Logger.php::get_monolog() decides the PSR/Log version at first call by running trait_exists('\Psr\Log\LoggerTrait'). WP-Stateless registers its v3 Psr\Log\ autoloader lazily (only when the Google client is instantiated), so on first call from Gravity PDF the trait isn't registered yet → shim falls into the v1 branch and runs:
class_alias( '\GFPDF_Vendor\Psr\Log\LoggerInterface', '\Psr\Log\LoggerInterface' );
This permanently binds the global \Psr\Log\LoggerInterface to the v1 signature. Later, when WP-Stateless boots its bundled Monolog 3, PHP rejects Monolog\Logger::emergency(string|\Stringable $message): void against the aliased v1 signature.
A second, structural issue: in vendor_prefixed/monolog/src/Monolog/Logger.php (and ~28 other files inside vendor_prefixed/), the \Psr\Log\ namespace was not prefixed by the build tool, e.g.:
class Logger implements \Psr\Log\LoggerInterface, \GFPDF_Vendor\Monolog\ResettableInterface
So Gravity PDF's own prefixed Monolog still depends on the global \Psr\Log\LoggerInterface resolving to v1, which is why vendor/psr/log/ still ships an unprefixed v1 alongside vendor_prefixed/psr/log/.
The result is that class_alias is needed every time another plugin loads PSR/Log v3 lazily after Gravity PDF has booted — and the compat shim's trait_exists check is a race against lazy autoloaders.
Suggested fix (one or more)
Replace trait_exists snapshot with an autoload-aware probe, or defer get_monolog() until plugins_loaded priority near PHP_INT_MAX so lazy autoloaders have registered.
Prefix every \Psr\Log\… reference inside vendor_prefixed/ so Gravity PDF's prefixed Monolog implements \GFPDF_Vendor\Psr\Log\LoggerInterface. Then drop the unprefixed vendor/psr/log/ ship and the global class_alias entirely.
Provide a filter or constant (e.g. GFPDF_FORCE_PSR_LOG_VERSION) so site owners can pin the target version when load-order detection is unreliable.