Skip to main content
Mediacurrent logo
Hero Background Image

Blog Post

Debugging Composer Dependency Conflicts

by Mediacurrent Team
October 26, 2021

Are you ready to upgrade to Drupal 9? If you're moving from a Drupal 8 site, it needs to be reviewed and updated to remove any deprecated code that will no longer be compatible with Drupal 9. Luckily, there are a few ways to check existing codebases for deprecated code, get a glimpse of what changes need to be made, and even apply the fixes automatically.

We have other blog posts that go into details about how to plan, prepare, and fix issues with deprecated code in preparation for Drupal 9, so we won’t go into those details here, but rather walk through a Composer issue we recently ran into while trying to get Drupal Check and Rector utilities added to perform our own code deprecation checks.

We hope that this blog post helps others with similar Composer issues figure out ways to understand and debug these cryptic errors and be aware of some options and things to try in fixing them.

The Conflict

The issue we faced was where a developer had already added the Drupal Check utility a while back, and when adding Rector, you may get Composer conflict messages like this:

"Your requirements could not be resolved to an installable set of packages.

Problem 1

    - rector/rector-prefixed v0.3.5 requires phpstan/phpstan ^0.11.19 -> satisfiable by phpstan/phpstan[0.11.19] but these conflict with your requirements or minimum-stability.

    - Installation request for palantirnet/drupal-rector ^0.5.1 -> satisfiable by palantirnet/drupal-rector[0.5.1].

    - Conclusion: remove nikic/php-parser v4.0.2

    - Conclusion: don't install nikic/php-parser v4.0.2

    - palantirnet/drupal-rector 0.5.1 requires rector/rector-prefixed <0.7.19 -> satisfiable by rector/rector-prefixed[v0.3.5, v0.6.10, v0.6.12, v0.6.13, v0.6.14, v0.6.2, v0.6.4, v0.6.5, v0.6.7, v0.6.8, v0.6.9, v0.7.0, v0.7.1, v0.7.10, v0.7.11, v0.7.12, v0.7.13, v0.7.14, v0.7.15, v0.7.16, v0.7.17, v0.7.18, v0.7.2, v0.7.3, v0.7.4, v0.7.5, v0.7.6, v0.7.7, v0.7.8, v0.7.9].

    - rector/rector-prefixed v0.6.10 conflicts with nikic/php-parser[v4.0.2].

    - rector/rector-prefixed v0.6.12 conflicts with nikic/php-parser[v4.0.2].

    - rector/rector-prefixed v0.6.13 conflicts with nikic/php-parser[v4.0.2].

    - rector/rector-prefixed v0.6.14 conflicts with nikic/php-parser[v4.0.2].

    - rector/rector-prefixed v0.6.2 conflicts with nikic/php-parser[v4.0.2].

    - rector/rector-prefixed v0.6.4 conflicts with nikic/php-parser[v4.0.2].

    - rector/rector-prefixed v0.6.5 conflicts with nikic/php-parser[v4.0.2].

    - rector/rector-prefixed v0.6.7 conflicts with nikic/php-parser[v4.0.2].

    - rector/rector-prefixed v0.6.8 conflicts with nikic/php-parser[v4.0.2].

    - rector/rector-prefixed v0.6.9 conflicts with nikic/php-parser[v4.0.2].

    - rector/rector-prefixed v0.7.0 conflicts with nikic/php-parser[v4.0.2].

    - rector/rector-prefixed v0.7.1 conflicts with nikic/php-parser[v4.0.2].

    - rector/rector-prefixed v0.7.10 conflicts with nikic/php-parser[v4.0.2].

    - rector/rector-prefixed v0.7.11 conflicts with nikic/php-parser[v4.0.2].

    - rector/rector-prefixed v0.7.12 conflicts with nikic/php-parser[v4.0.2].

    - rector/rector-prefixed v0.7.13 conflicts with nikic/php-parser[v4.0.2].

    - rector/rector-prefixed v0.7.14 conflicts with nikic/php-parser[v4.0.2].

    - rector/rector-prefixed v0.7.15 conflicts with nikic/php-parser[v4.0.2].

    - rector/rector-prefixed v0.7.16 conflicts with nikic/php-parser[v4.0.2].

    - rector/rector-prefixed v0.7.17 conflicts with nikic/php-parser[v4.0.2].

    - rector/rector-prefixed v0.7.18 conflicts with nikic/php-parser[v4.0.2].

    - rector/rector-prefixed v0.7.2 conflicts with nikic/php-parser[v4.0.2].

    - rector/rector-prefixed v0.7.3 conflicts with nikic/php-parser[v4.0.2].

    - rector/rector-prefixed v0.7.4 conflicts with nikic/php-parser[v4.0.2].

    - rector/rector-prefixed v0.7.5 conflicts with nikic/php-parser[v4.0.2].

    - rector/rector-prefixed v0.7.6 conflicts with nikic/php-parser[v4.0.2].

    - rector/rector-prefixed v0.7.7 conflicts with nikic/php-parser[v4.0.2].

    - rector/rector-prefixed v0.7.8 conflicts with nikic/php-parser[v4.0.2].

    - rector/rector-prefixed v0.7.9 conflicts with nikic/php-parser[v4.0.2].

    - Installation request for nikic/php-parser 4.0.2 -> satisfiable by nikic/php-parser[v4.0.2].

Installation failed, reverting ./composer.json to its original content.

This can be pretty scary to look at and digest what it all means. But, let’s just start at the top.

Step 1

The first problem stated is:

- rector/rector-prefixed v0.3.5 requires phpstan/phpstan ^0.11.19 -> satisfiable by phpstan/phpstan[0.11.19] but these conflict with your requirements or minimum-stability.

So, first, let's look at the composer.json file. We only really care about the “require-dev” section, since we’re only dealing with the development utility scripts Drupal Check and Rector in this example, but these same investigation and debugging steps in Composer can apply similarly to items in the “require” section as well, like Drupal modules and their dependencies.

"require-dev": {

   "drupal/drupal-extension": "^3.4",

   "drush-ops/behat-drush-endpoint": "^8.2.4",

   "mediacurrent/ci-scripts": "~1.2",

   "mediacurrent/ci-tests": "dev-master",

   "mediacurrent/mis_vagrant": "^5.1.0",

   "mglaman/drupal-check": "^1.0",

   "nikic/php-parser": "4.0.2",

   "phpro/grumphp": "^0.11.6",

   "phpstan/phpstan": "0.11.9",

   "webflo/drupal-core-require-dev": "^8.8.1"

},

Notice how there is a strict version set for the phpstan package? What’s happening is the Rector tool is trying to add a dependency package, rector/rector-prefixed v0.3.5, but that requires phpstan ^0.11.19 (so 0.11.19 or greater). And because we have a strict 0.11.9 for phpstan in composer.json, it can’t add what it needs.

A first attempt to fix this would be to try installing a version of phpstan that it wants, so we can try something like:

composer require --dev phpstan/phpstan:^0.11.19

After running that, it looks better, but still some issues:

Your requirements could not be resolved to an installable set of packages.

Problem 1

 - Can only install one of: nikic/php-parser[v4.0.2, 4.3.x-dev].

    - Can only install one of: nikic/php-parser[4.3.x-dev, v4.0.2].

    - Can only install one of: nikic/php-parser[4.3.x-dev, v4.0.2].

    - phpstan/phpstan 0.11.19 requires nikic/php-parser ^4.2.3 -> satisfiable by nikic/php-parser[4.3.x-dev].

    - Installation request for phpstan/phpstan ^0.11.19 -> satisfiable by phpstan/phpstan[0.11.19].

    - Installation request for nikic/php-parser 4.0.2 -> satisfiable by nikic/php-parser[v4.0.2].

That issue is caused because of more strict package versions in composer.json -- especially with the nikic/php-parser package.

"nikic/php-parser": "4.0.2"

This version constraint is causing this issue:

- phpstan/phpstan 0.11.19 requires nikic/php-parser ^4.2.3 -> satisfiable by nikic/php-parser[4.3.x-dev].

Step 2

Upon further inspection in the repo and commit history, we’ve concluded that the previous developer added those packages manually to the composer.json file (well, Composer-required them), but they shouldn’t have been added in that way, since they should be letting Composer manage them as dependencies.

Sometimes when debugging Composer dependencies we try one strategy and if that doesn't work we revert back and try something different.

Now that it seems that these packages were added manually to the projects in error, we can pull them out of the codebase and let Composer manage them as dependencies in a way it needs.

Remove the phpstan package from composer.json:

composer remove phpstan/phpstan

It looks like this removed the package from composer.json, and updated the package to a newer version because phpstan is still a dependency of Drupal-check’s constraint set at ^0.11.9. And 0.11.12 is the latest version in that constraint.

But, it’s still not going to be good enough, because remember Drupal Rector rector-prefixed package needs at least 0.11.19 per the ^0.11.19 constraint.

Step 3

Remove the php-parser package from composer.json:

composer remove nikic/php-parser

It looks like it removed the php-parser package from composer.json, and updated the package to v4.4.0

Loading composer repositories with package information

Updating dependencies (including require-dev)

Package operations: 0 installs, 1 update, 0 removals

Gathering patches for root package.

Gathering patches for dependencies. This might take a minute.

  - Updating nikic/php-parser (v4.0.2 => v4.4.0): Loading from cache

That’s fine, we’ll just let Composer manage the dependencies itself, but we’ve cleaned up the composer.json of packages that shouldn’t have been there and were conflicting.

Let’s see if we can get Drupal Rector added now that the conflicting packages are removed:

composer require --dev palantirnet/drupal-rector

Nope, still some of the same issues as in the beginning:

Loading composer repositories with package information

Updating dependencies (including require-dev)

Your requirements could not be resolved to an installable set of packages.

  Problem 1

    - Installation request for palantirnet/drupal-rector ^0.5.1 -> satisfiable by palantirnet/drupal-rector[0.5.1].

    - Conclusion: remove phpstan/phpstan 0.11.12

    - Conclusion: don't install phpstan/phpstan 0.11.12

    - rector/rector-prefixed v0.3.5 requires phpstan/phpstan ^0.11.19 -> satisfiable by phpstan/phpstan[0.11.19].

    - palantirnet/drupal-rector 0.5.1 requires rector/rector-prefixed <0.7.19 -> satisfiable by rector/rector-prefixed[v0.3.5, v0.6.10, v0.6.12, v0.6.13, v0.6.14, v0.6.2, v0.6.4, v0.6.5, v0.6.7, v0.6.8, v0.6.9, v0.7.0, v0.7.1, v0.7.10, v0.7.11, v0.7.12, v0.7.13, v0.7.14, v0.7.15, v0.7.16, v0.7.17, v0.7.18, v0.7.2, v0.7.3, v0.7.4, v0.7.5, v0.7.6, v0.7.7, v0.7.8, v0.7.9].

    - Can only install one of: phpstan/phpstan[0.11.19, 0.11.12].

    - rector/rector-prefixed v0.6.10 conflicts with phpstan/phpstan[0.11.12].

    - rector/rector-prefixed v0.6.12 conflicts with phpstan/phpstan[0.11.12].

    - rector/rector-prefixed v0.6.13 conflicts with phpstan/phpstan[0.11.12].

    - rector/rector-prefixed v0.6.14 conflicts with phpstan/phpstan[0.11.12].

    - rector/rector-prefixed v0.6.2 conflicts with phpstan/phpstan[0.11.12].

    - rector/rector-prefixed v0.6.4 conflicts with phpstan/phpstan[0.11.12].

    - rector/rector-prefixed v0.6.5 conflicts with phpstan/phpstan[0.11.12].

    - rector/rector-prefixed v0.6.7 conflicts with phpstan/phpstan[0.11.12].

    - rector/rector-prefixed v0.6.8 conflicts with phpstan/phpstan[0.11.12].

    - rector/rector-prefixed v0.6.9 conflicts with phpstan/phpstan[0.11.12].

    - rector/rector-prefixed v0.7.0 conflicts with phpstan/phpstan[0.11.12].

    - rector/rector-prefixed v0.7.1 conflicts with phpstan/phpstan[0.11.12].

    - rector/rector-prefixed v0.7.10 conflicts with phpstan/phpstan[0.11.12].

    - rector/rector-prefixed v0.7.11 conflicts with phpstan/phpstan[0.11.12].

    - rector/rector-prefixed v0.7.12 conflicts with phpstan/phpstan[0.11.12].

    - rector/rector-prefixed v0.7.13 conflicts with phpstan/phpstan[0.11.12].

    - rector/rector-prefixed v0.7.14 conflicts with phpstan/phpstan[0.11.12].

    - rector/rector-prefixed v0.7.15 conflicts with phpstan/phpstan[0.11.12].

    - rector/rector-prefixed v0.7.16 conflicts with phpstan/phpstan[0.11.12].

    - rector/rector-prefixed v0.7.17 conflicts with phpstan/phpstan[0.11.12].

    - rector/rector-prefixed v0.7.18 conflicts with phpstan/phpstan[0.11.12].

    - rector/rector-prefixed v0.7.2 conflicts with phpstan/phpstan[0.11.12].

    - rector/rector-prefixed v0.7.3 conflicts with phpstan/phpstan[0.11.12].

    - rector/rector-prefixed v0.7.4 conflicts with phpstan/phpstan[0.11.12].

    - rector/rector-prefixed v0.7.5 conflicts with phpstan/phpstan[0.11.12].

    - rector/rector-prefixed v0.7.6 conflicts with phpstan/phpstan[0.11.12].

    - rector/rector-prefixed v0.7.7 conflicts with phpstan/phpstan[0.11.12].

    - rector/rector-prefixed v0.7.8 conflicts with phpstan/phpstan[0.11.12].

    - rector/rector-prefixed v0.7.9 conflicts with phpstan/phpstan[0.11.12].

    - Installation request for phpstan/phpstan (locked at 0.11.12) -> satisfiable by phpstan/phpstan[0.11.12].

Installation failed, reverting ./composer.json to its original content.

Step 4

So let’s dive deeper. Looking at the Drupal Check’s composer.json, we can see phpstan is listed as a dependency, so why are we including phpstan in our own composer.json?

"phpstan/phpstan": "^0.12"

Well, that’s on the latest (master) version of Drupal check:

https://github.com/mglaman/drupal-check/blob/master/composer.json

Running this command, we can see the version of Drupal check we're currently running is:
./vendor/bin/drupal-check --version

Drupal Check 1.0.13

So, let’s check this version’s composer.json instead:

https://github.com/mglaman/drupal-check/blob/1.0.13/composer.json

We can see it’s still 

"phpstan/phpstan": "^0.11.9"
Update phpstan
Loading composer repositories with package information

Updating dependencies (including require-dev)

Package operations: 0 installs, 1 update, 0 removals

Gathering patches for root package.

Gathering patches for dependencies. This might take a minute.

  - Updating phpstan/phpstan (0.11.12 => 0.11.19): Loading from cache

Now we have the right version we’re needing for Drupal Rector.

Loading composer repositories with package information

Updating dependencies (including require-dev)

Package operations: 3 installs, 0 updates, 0 removals

Gathering patches for root package.

Gathering patches for dependencies. This might take a minute.

  - Installing rector/rector-prefixed (v0.3.5): Loading from cache

  - Installing jawira/case-converter (v1.2.0): Loading from cache

  - Installing palantirnet/drupal-rector (0.5.1): Loading from cache

Success!

So that seems fishy -- because Drupal Check has a dependency of phpstan ^0.12, but we already have a phpstan 0.11.9 in our composer.json file. Why do we even have phpstan listed in our “require-dev”?

So next, we’re going to try unwinding some things and see if we can get this working.

Step 5

Let’s first remove Drupal Check:

composer remove phpstan/phpstan

This results in a few updates, most notably phpstan being updated to 0.11.12, which matches to the ^0.11.9 constraint set forth for the version of Drupal check we’re using.

Updating dependencies (including require-dev)                                                                         

Package operations: 0 installs, 13 updates, 0 removals

Gathering patches for root package.

Gathering patches for dependencies. This might take a minute.

  - Updating ocramius/package-versions (1.4.0 => 1.4.2): Loading from cache

  - Updating symfony/debug (v3.4.39 => v3.4.40): Loading from cache

  - Updating symfony/finder (v3.4.39 => v3.4.40): Loading from cache

  - Updating symfony/console (v3.4.39 => v3.4.40): Loading from cache

  - Updating nette/utils (v3.0.1 => v3.1.1): Loading from cache

  - Updating nette/schema (v1.0.0 => v1.0.2): Loading from cache

  - Updating nette/finder (v2.5.1 => v2.5.2): Loading from cache

  - Updating nette/robot-loader (v3.2.0 => v3.2.3): Loading from cache

  - Updating nette/php-generator (v3.2.3 => v3.3.4): Loading from cache

  - Updating nette/neon (v3.0.0 => v3.1.2): Loading from cache

  - Updating nette/di (v3.0.1 => v3.0.3): Loading from cache

  - Updating nette/bootstrap (v3.0.0 => v3.0.1): Loading from cache

  - Updating phpstan/phpstan (0.11.9 => 0.11.12): Loading from cache

And we know that this php-parser package was added manually as well, similar to how phpstan was added manually, so we can remove it too. There is no reason to add these dependency packages manually, we can just let Composer manage them.

composer remove nikic/php-parser
Running that results in this output:
Updating dependencies (including require-dev)                                                                         

Package operations: 0 installs, 1 update, 0 removals

Gathering patches for root package.

Gathering patches for dependencies. This might take a minute.

  - Updating nikic/php-parser (v4.0.2 => v4.4.0): Loading from cache

Using Composer why nikic/php-parser, we can see why the nikic/php-parser package is needed

phpstan/phpstan                    0.11.12  requires  nikic/php-parser (^4.0.2)

phpstan/phpstan-deprecation-rules  0.11.2   requires  nikic/php-parser (^4.0)

psy/psysh                          v0.9.9   requires  nikic/php-parser (~1.3|~2.0|~3.0|~4.0)

Step 6

Let's upgrade Drupal check

composer update mglaman/drupal-check --with-dependencies

Updating dependencies (including require-dev)                                                                         

Package operations: 0 installs, 3 updates, 0 removals

Gathering patches for root package.

Gathering patches for dependencies. This might take a minute.

  - Updating phpstan/phpstan (0.11.12 => 0.11.19): Loading from cache

  - Updating symfony/yaml (v3.4.39 => v3.4.40): Loading from cache

  - Updating mglaman/drupal-check (1.0.13 => 1.0.14): Loading from cache

Ah ha! It looks like we’re now on the right version of phpstan 0.11.19 that will support us in adding the Drupal Rector

Let’s try adding Drupal Rector again now:

composer require --dev palantirnet/drupal-rector

Updating dependencies (including require-dev)                                                                         

Package operations: 3 installs, 0 updates, 0 removals

Gathering patches for root package.

Gathering patches for dependencies. This might take a minute.

  - Installing rector/rector-prefixed (v0.3.5): Loading from cache

  - Installing jawira/case-converter (v1.2.0): Loading from cache

  - Installing palantirnet/drupal-rector (0.5.1): Loading from cache

Remember back to the first Composer issue we looked at with the “rector/rector-prefixed” package? We can now see that Rector was successfully able to add it.

Gathering patches for dependencies. This might take a minute.

  - Installing rector/rector-prefixed (v0.7.18): Loading from cache

  - Installing jawira/case-converter (v1.2.0): Loading from cache

  - Installing palantirnet/drupal-rector (0.5.1): Loading from cache

And there are currently no other Composer issues being thrown at us.

The Final Step for a Clean Solution

We discovered that local dependencies were being locked to a specific version and by removing those, Composer was able to correctly reconcile the dependencies for these packages. This is somewhat dependent on and specific to your own build processes and environments, but you should be set to run Drupal Check and Rector and begin your journey and preparations for Drupal 9.

Final cleanest, best solution in our opinion...

Packages added manually, but should have just been added as dependencies and managed by Composer:

composer remove phpstan/phpstan

composer remove nikic/php-parser



Updated drupal-finder

composer update webflo/drupal-finder

Loading composer repositories with package information

Updating dependencies (including require-dev)

Package operations: 0 installs, 1 update, 0 removals

Gathering patches for root package.

Gathering patches for dependencies. This might take a minute.

  - Updating webflo/drupal-finder (1.1.0 => 1.2.0): Loading from cache



composer update mglaman/drupal-check --with-dependencies

Loading composer repositories with package information

Updating dependencies (including require-dev)

Package operations: 0 installs, 5 updates, 7 removals

  - Removing phpstan/phpdoc-parser (0.3.5)

  - Removing nette/schema (v1.0.2)

  - Removing nette/robot-loader (v3.2.3)

  - Removing nette/php-generator (v3.3.4)

  - Removing nette/di (v3.0.3)

  - Removing nette/bootstrap (v3.0.1)

  - Removing mglaman/phpstan-junit (0.11.2)

Gathering patches for root package.

Gathering patches for dependencies. This might take a minute.

  - Updating phpstan/phpstan (0.11.12 => 0.12.23): Loading from cache

  - Updating phpstan/phpstan-deprecation-rules (0.11.2 => 0.12.2): Loading from cache

  - Updating symfony/yaml (v3.4.39 => v3.4.40): Loading from cache

  - Updating mglaman/phpstan-drupal (0.11.10 => 0.12.3): Loading from cache

  - Updating mglaman/drupal-check (1.0.13 => 1.1.1): Loading from cache



composer require --dev palantirnet/drupal-rector

Still not confident about your preparedness to upgrade, or short on time or team capacity? We can help you get ready for Drupal 9

Related Insights