Because there is a 2.3.1
and 2.x
release, Composer constraint ^2.3 installs 2.x-dev
instead of the stable 2.3.1
, because Composer treats the numeric branch 2.x
as a higher version than 2.3.1
, even with prefer-stable: true
.
Explanation
(with some help from ChatGPT)
The caret operator ^2.3 expands to the range >=2.3.0 <3.0.0. Composer builds an internal list of all matching refs (tags 2.3.0, 2.3.1 and the branch “2.x” as a dev branch) and always picks the highest numeric version first, then considers stability.
Editor Advanced Link's 2.x release is treated as a numeric feature branch (2.x-dev), which Composer interprets like “2.999.0‑dev”—higher than 2.3.1—and thus prefers it, even with "prefer-stable": true, because that setting only breaks ties within a given version.
Composer’s resolver works in two clearly documented stages:
“When Composer has a complete list of available versions from your VCS, it then finds the highest version that matches all version constraints in your project … and it downloads … that tag.”
getcomposer.org
That means it looks at every matching tag and branch (including dev-2.x), normalizes them (e.g. dev-2.x becomes something like 2.999.0‑dev) and picks the numerically greatest candidate—before looking at stability.
Once the highest numeric version is chosen, Composer looks at stability to decide between, say, 2.3.1 vs. 2.3.1‑dev. That’s where prefer-stable: true can nudge you toward the stable tag when two candidates share the same version number. But it never goes back and replaces “2.999.0‑dev” with “2.3.1” because that would be choosing a lower numeric version.
In short, Composer’s “pick highest version” step is strictly numeric, and prefer-stable only applies to break ties within a given normalized version, not to override the numeric ordering itself.
composer.json
:
"minimum-stability": "dev",
"prefer-stable": true,
composer require drupal/editor_advanced_link:^2.3
dev‑2.x
instead of the current release 2.3.1
.
Remove (unpublish) the 2.x dev release (and its branch).
Without the “2.x” dev entry, the ^2.3 constraint will correctly resolve to the latest stable 2.3.1.
Rather than the commonly used caret (^) constraint, specify the exact version desired (e.g. 2.3.1).
Active
2.0
Code