diff --git a/automatic_updates_extensions/tests/src/Build/ModuleUpdateTest.php b/automatic_updates_extensions/tests/src/Build/ModuleUpdateTest.php
index d557b41dc633f696eacae51fe39c8c541add6f54..c3b642998db7ba6c416441b1f14b5b517d2ba906 100644
--- a/automatic_updates_extensions/tests/src/Build/ModuleUpdateTest.php
+++ b/automatic_updates_extensions/tests/src/Build/ModuleUpdateTest.php
@@ -93,7 +93,7 @@ END;
     );
 
     $module_composer_json = json_decode($file_contents['web/modules/contrib/alpha/composer.json']);
-    $this->assertSame('1.1.0', $module_composer_json->version);
+    $this->assertSame('1.1.0', $module_composer_json?->version);
   }
 
   /**
diff --git a/package_manager/src/ComposerInspector.php b/package_manager/src/ComposerInspector.php
index 72592bd5d1bab7bcfb9783e087f764f2f730f60d..5954499f4cd3971b46fa66ee979e3b3260011f82 100644
--- a/package_manager/src/ComposerInspector.php
+++ b/package_manager/src/ComposerInspector.php
@@ -369,7 +369,7 @@ class ComposerInspector implements LoggerAwareInterface {
    */
   private function getPackageTypes(array $packages_data, string $working_dir): array {
     $lock_content = file_get_contents($working_dir . DIRECTORY_SEPARATOR . 'composer.lock');
-    $lock_data = json_decode($lock_content, TRUE, 512, JSON_THROW_ON_ERROR);
+    $lock_data = json_decode($lock_content, TRUE, flags: JSON_THROW_ON_ERROR);
 
     $lock_packages = array_merge($lock_data['packages'] ?? [], $lock_data['packages-dev'] ?? []);
     foreach ($lock_packages as $lock_package) {
diff --git a/package_manager/src/FailureMarker.php b/package_manager/src/FailureMarker.php
index 2287e983450082afda60ce790320a65ddb311964..38a05e24e6cafbec27d09941d686713a03d6d395 100644
--- a/package_manager/src/FailureMarker.php
+++ b/package_manager/src/FailureMarker.php
@@ -79,7 +79,7 @@ final class FailureMarker {
     if (file_exists($path)) {
       $data = file_get_contents($path);
       try {
-        $data = json_decode($data, TRUE, 512, JSON_THROW_ON_ERROR);
+        $data = json_decode($data, TRUE, flags: JSON_THROW_ON_ERROR);
       }
       catch (\JsonException $exception) {
         throw new StageFailureMarkerException('Failure marker file exists but cannot be decoded.', $exception->getCode(), $exception);
diff --git a/package_manager/src/ProcessOutputCallback.php b/package_manager/src/ProcessOutputCallback.php
index f5896c94b4c9c0d33908136b071de740a5e2350e..8ce662508784612b0d4ed9cfacdb0579fb593c24 100644
--- a/package_manager/src/ProcessOutputCallback.php
+++ b/package_manager/src/ProcessOutputCallback.php
@@ -84,7 +84,7 @@ final class ProcessOutputCallback implements ProcessOutputCallbackInterface, Log
   public function parseJsonOutput(): mixed {
     $output = $this->getOutput();
     if ($output !== NULL) {
-      return json_decode($output, TRUE, 512, JSON_THROW_ON_ERROR);
+      return json_decode($output, TRUE, flags: JSON_THROW_ON_ERROR);
     }
     return NULL;
   }
diff --git a/package_manager/src/Validator/AllowedScaffoldPackagesValidator.php b/package_manager/src/Validator/AllowedScaffoldPackagesValidator.php
index b5c9b4fe826e2df29199f63b3ed03313378affaf..c0e439d5b437fbc0ee1096b4b5101a9eeb9bcf92 100644
--- a/package_manager/src/Validator/AllowedScaffoldPackagesValidator.php
+++ b/package_manager/src/Validator/AllowedScaffoldPackagesValidator.php
@@ -4,6 +4,7 @@ declare(strict_types = 1);
 
 namespace Drupal\package_manager\Validator;
 
+use Drupal\Component\Serialization\Json;
 use Drupal\Core\StringTranslation\StringTranslationTrait;
 use Drupal\package_manager\Event\StatusCheckEvent;
 use Symfony\Component\EventDispatcher\EventSubscriberInterface;
@@ -52,7 +53,7 @@ final class AllowedScaffoldPackagesValidator implements EventSubscriberInterface
       "drupal/legacy-scaffold-assets",
       "drupal/core",
     ];
-    $extra = json_decode($this->composerInspector->getConfig('extra', $path . '/composer.json'), TRUE);
+    $extra = Json::decode($this->composerInspector->getConfig('extra', $path . '/composer.json'));
     $allowed_packages = $extra['drupal-scaffold']['allowed-packages'] ?? [];
     $extra_packages = array_diff($allowed_packages, $implicitly_allowed_packages);
     if (!empty($extra_packages)) {
diff --git a/package_manager/src/Validator/ComposerPluginsValidator.php b/package_manager/src/Validator/ComposerPluginsValidator.php
index 7664ec820e5049baf009f00f788bd113ef0d2f2b..d2a23e8e91f07c4630fe41f3907635e24721dd28 100644
--- a/package_manager/src/Validator/ComposerPluginsValidator.php
+++ b/package_manager/src/Validator/ComposerPluginsValidator.php
@@ -5,7 +5,6 @@ declare(strict_types = 1);
 namespace Drupal\package_manager\Validator;
 
 use Composer\Semver\Semver;
-use Drupal\Component\Serialization\Json;
 use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\StringTranslation\StringTranslationTrait;
 use Drupal\package_manager\ComposerInspector;
@@ -167,7 +166,7 @@ final class ComposerPluginsValidator implements EventSubscriberInterface {
       $allowed_plugins = ComposerInspector::toBoolean($value);
     }
     catch (\UnhandledMatchError) {
-      $allowed_plugins = Json::decode($value);
+      $allowed_plugins = json_decode($value, TRUE, flags: JSON_THROW_ON_ERROR);
     }
 
     if ($allowed_plugins === TRUE) {
diff --git a/package_manager/tests/modules/fixture_manipulator/src/FixtureManipulator.php b/package_manager/tests/modules/fixture_manipulator/src/FixtureManipulator.php
index 424bb71a938b9dc854735e408e8707df99407508..71ecc8c9fbfaf9ad2cb2f4574278d27c49787fa4 100644
--- a/package_manager/tests/modules/fixture_manipulator/src/FixtureManipulator.php
+++ b/package_manager/tests/modules/fixture_manipulator/src/FixtureManipulator.php
@@ -111,7 +111,7 @@ class FixtureManipulator {
     // `composer require` happily will re-require already required packages.
     // Prevent test authors from thinking this has any effect when it does not.
     $json = $this->runComposerCommand(['show', '--name-only', '--format=json'])->stdout;
-    $installed_package_names = array_column(json_decode($json)->installed, 'name');
+    $installed_package_names = array_column(json_decode($json)?->installed ?? [], 'name');
     if (in_array($package['name'], $installed_package_names)) {
       throw new \LogicException(sprintf("Expected package '%s' to not be installed, but it was.", $package['name']));
     }
@@ -570,7 +570,7 @@ class FixtureManipulator {
     if ($is_new_or_fork === 'fork') {
       $original_composer_json_path = $repo_path . DIRECTORY_SEPARATOR . 'composer.json';
       $original_repo_path = $repo_path;
-      $original_composer_json_data = json_decode(file_get_contents($original_composer_json_path), TRUE);
+      $original_composer_json_data = json_decode(file_get_contents($original_composer_json_path), TRUE, flags: JSON_THROW_ON_ERROR);
       $forked_composer_json_data = NestedArray::mergeDeep($original_composer_json_data, $package);
       if ($original_composer_json_data === $forked_composer_json_data) {
         throw new \LogicException(sprintf('Nothing is actually different in this fork of the package %s.', $package['name']));
@@ -592,7 +592,7 @@ class FixtureManipulator {
     // must have unique versions).
     $repo_key = "repo.$name";
     if ($is_new_or_fork === 'fork') {
-      $repositories = json_decode(file_get_contents($this->dir . '/composer.json'), TRUE)['repositories'];
+      $repositories = json_decode(file_get_contents($this->dir . '/composer.json'), TRUE, flags: JSON_THROW_ON_ERROR)['repositories'];
       // @todo consistently use 'version' or 'options.versions.PACKAGE_NAME', by fixing ComposerFixtureCreator in https://drupal.org/i/3347055
       $original_version = isset($repositories[$name]['version']) ? $repositories[$name]['version'] : $repositories[$name]['options']['versions'][$name];
       if ($package['version'] !== $original_version) {
diff --git a/package_manager/tests/src/Build/PackageUpdateTest.php b/package_manager/tests/src/Build/PackageUpdateTest.php
index 85eb9f79906ffe91b8c504d6e2ece35118d46626..1f05874a8edd5295a4e8b2fb780f1833af12f669 100644
--- a/package_manager/tests/src/Build/PackageUpdateTest.php
+++ b/package_manager/tests/src/Build/PackageUpdateTest.php
@@ -68,7 +68,7 @@ class PackageUpdateTest extends TemplateProjectTestBase {
     foreach ($expected_versions as $module_name => $expected_version) {
       $path = "web/modules/contrib/$module_name/composer.json";
       $module_composer_json = json_decode($file_contents[$path]);
-      $this->assertSame($expected_version, $module_composer_json->version);
+      $this->assertSame($expected_version, $module_composer_json?->version);
     }
     // The post-apply event subscriber in updated_module 1.1.0 should have
     // created this file.
diff --git a/package_manager/tests/src/Build/TemplateProjectTestBase.php b/package_manager/tests/src/Build/TemplateProjectTestBase.php
index 6b01c1a98c31b38a270258a51dbfc433b9f46bca..eca757b3900d12fde07da1d0c091730bb76b1309 100644
--- a/package_manager/tests/src/Build/TemplateProjectTestBase.php
+++ b/package_manager/tests/src/Build/TemplateProjectTestBase.php
@@ -343,7 +343,7 @@ END;
         $package_info = $path . '/composer.json';
         $this->assertFileIsReadable($package_info);
         $package_info = file_get_contents($package_info);
-        $package_info = json_decode($package_info, TRUE, 512, JSON_THROW_ON_ERROR);
+        $package_info = json_decode($package_info, TRUE, flags: JSON_THROW_ON_ERROR);
 
         $version = $installed_package['version'];
         // Create a pared-down package definition that has just enough
@@ -412,7 +412,7 @@ END;
 
     $output = trim($output);
     if ($json) {
-      $output = json_decode($output, TRUE, JSON_THROW_ON_ERROR);
+      $output = json_decode($output, TRUE, flags: JSON_THROW_ON_ERROR);
     }
     return $output;
   }
@@ -570,7 +570,7 @@ END;
       $mink->assertSession()->statusCodeEquals(200);
     }
 
-    return json_decode($file_contents, TRUE);
+    return json_decode($file_contents, TRUE, flags: JSON_THROW_ON_ERROR);
   }
 
   // BEGIN: DELETE FROM CORE MERGE REQUEST.
@@ -590,7 +590,7 @@ END;
     $file = $this->getWorkspaceDirectory() . '/composer/Metapackage/CoreRecommended/composer.json';
     $this->assertFileIsWritable($file);
     $data = file_get_contents($file);
-    $data = json_decode($data, TRUE);
+    $data = json_decode($data, TRUE, flags: JSON_THROW_ON_ERROR);
     unset($data['require']['drupal/automatic_updates']);
     file_put_contents($file, json_encode($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
   }
diff --git a/package_manager/tests/src/Kernel/FixtureManipulatorTest.php b/package_manager/tests/src/Kernel/FixtureManipulatorTest.php
index b8d5a27748a6c4d86d498edd1d727541b2d08c89..679e308be67806cff6f5417dd897d5020cab6f27 100644
--- a/package_manager/tests/src/Kernel/FixtureManipulatorTest.php
+++ b/package_manager/tests/src/Kernel/FixtureManipulatorTest.php
@@ -146,7 +146,7 @@ class FixtureManipulatorTest extends PackageManagerKernelTestBase {
     // Assert ::modifyPackage() works with a package in an existing fixture not
     // created by ::addPackage().
     $decode_composer_json = function ($package_name): array {
-      return json_decode(file_get_contents($this->dir . "/vendor/$package_name/composer.json"), TRUE, 512, JSON_THROW_ON_ERROR);
+      return json_decode(file_get_contents($this->dir . "/vendor/$package_name/composer.json"), TRUE, flags: JSON_THROW_ON_ERROR);
     };
     $original_composer_json = $decode_composer_json('my/dev-package');
     (new ActiveFixtureManipulator())
diff --git a/package_manager/tests/src/Kernel/LockFileValidatorTest.php b/package_manager/tests/src/Kernel/LockFileValidatorTest.php
index 949fed6574f19cd96afd00b5e5ce51ae142a02d1..dc4791d1800048fdcb20fcf48f32589a5a8ddcb4 100644
--- a/package_manager/tests/src/Kernel/LockFileValidatorTest.php
+++ b/package_manager/tests/src/Kernel/LockFileValidatorTest.php
@@ -101,7 +101,7 @@ class LockFileValidatorTest extends PackageManagerKernelTestBase {
     // priority of 0, this listener changes lock file before the validator
     // runs.
     $this->addEventTestListener(function () {
-      $lock = json_decode(file_get_contents($this->activeDir . '/composer.lock'), TRUE);
+      $lock = json_decode(file_get_contents($this->activeDir . '/composer.lock'), TRUE, flags: JSON_THROW_ON_ERROR);
       $lock['extra']['key'] = 'value';
       file_put_contents($this->activeDir . '/composer.lock', json_encode($lock, JSON_THROW_ON_ERROR));
     }, $event_class);
diff --git a/package_manager/tests/src/Traits/ComposerInstallersTrait.php b/package_manager/tests/src/Traits/ComposerInstallersTrait.php
index 354e08be64f00bc9581624e8f5e7fe8612305143..dd36538a262229debdf7b44c162f4f3f7ca1c4ef 100644
--- a/package_manager/tests/src/Traits/ComposerInstallersTrait.php
+++ b/package_manager/tests/src/Traits/ComposerInstallersTrait.php
@@ -59,7 +59,7 @@ trait ComposerInstallersTrait {
     // Ensure Drupal core's default installer paths are also respected.
     $extra = $this->container->get(ComposerInspector::class)
       ->getConfig('extra', $this->getDrupalRoot() . '/composer.json');
-    $core_project_installer_paths = json_decode($extra, TRUE, 512, JSON_THROW_ON_ERROR)['installer-paths'];
+    $core_project_installer_paths = json_decode($extra, TRUE, flags: JSON_THROW_ON_ERROR)['installer-paths'];
 
     (new FixtureManipulator())
       ->addConfig([
diff --git a/tests/src/Build/CoreUpdateTest.php b/tests/src/Build/CoreUpdateTest.php
index db1a82f3c85df1877a5ffa1faea6177a7e7a5afc..87dbc7a134ebd5fb2c01a3b6afcc8462e2f05af4 100644
--- a/tests/src/Build/CoreUpdateTest.php
+++ b/tests/src/Build/CoreUpdateTest.php
@@ -134,7 +134,7 @@ class CoreUpdateTest extends UpdateTestBase {
     // Even though the response is what we expect, assert the status code as
     // well, to be extra-certain that there was no kind of server-side error.
     $this->assertSame(200, $update_status_code);
-    $file_contents = json_decode($file_contents, TRUE, 512, JSON_THROW_ON_ERROR);
+    $file_contents = json_decode($file_contents, TRUE, flags: JSON_THROW_ON_ERROR);
 
     $this->assertStringContainsString("const VERSION = '9.8.1';", $file_contents['web/core/lib/Drupal.php']);
     $this->assertUpdateSuccessful('9.8.1');