composer why-not vendor/package:version是唯一准确定位阻塞链的命令,它从根依赖逆推,逐层揭示谁拒绝该版本,首行“Root package requires”常暴露手动约束过窄。

composer why-not 是唯一能准确定位阻塞链的命令
报错里出现 Conclusion: don't install vendor/package:version,不是网络或权限问题,是 Composer 的 SAT 求解器确认“数学上无解”。composer why-not 不猜测、不回退,而是从根依赖逆向逐层输出谁在拒绝这个版本。
必须带完整包名和精确版本号,例如:composer why-not laravel/framework:11.0.0。只写 laravel/framework 会报 [InvalidArgumentException] Package not found。
- 输出第一行通常是
Root package requires "php": "8.1"——说明是你自己写的约束太窄 - 中间行如
spatie/laravel-backup v7.2.0 requires laravel/framework ^8.0——查 Packagist 确认它是否已支持 Laravel 11 - 末尾出现
(replaced by symfony/console v6.0.0)或conflict with foo/bar >=2.0——这是硬性排斥,无法靠改上层绕过
用 composer show --tree + grep 快速抓真实依赖路径
composer show --tree 读的是 vendor/ 和 composer.lock,不是 composer.json 的愿望清单。它告诉你项目里「真正长出来的树」,但默认输出太长,关键信息容易淹没。
加过滤才能准确定位:
-
composer show --tree | grep "guzzlehttp/guzzle"—— 查某个包被谁拉入、锁在哪个版本 -
composer show --tree monolog/monolog | grep -A5 -B5 "psr/log"—— 查两个包之间的真实传递路径 - 看到某行末尾标着
(locked to 7.8.1)或(replaced)—— 说明这个版本已被固定,改composer.json上层约束无效
别信 composer depends,它不反映版本限制
composer depends vendor/package 只回答“谁依赖它”,但不体现具体版本要求。比如 A 包 require "monolog/monolog": "^2.0",B 包 require "monolog/monolog": "^1.25",depends 输出里都只显示 A 和 B,看不出冲突根源。
工作流任务拆解与模型编排技能。使用场景:(1) 收到复杂工作任务需要拆解为可执行步骤,(2) 需要为不同步骤选择最合适的模型,(3) 需要跟踪工作流进度和模型使用情况,(4) 长时间任务卡住需要问题诊断和解决方案。
真要查约束源,得用:
-
composer depends -r vendor/package—— 加-r才递归查所有传递依赖,输出中带requires的行才是真约束来源 -
composer prohibits vendor/package:version—— 反向查谁依赖了不兼容的旧版,适合排查隐性锁死 -
composer show vendor/package—— 看它的requires、conflict、provides字段,有些包直接声明"conflict": {"laravel/framework": ">=11"}
执行 composer update --dry-run -v 暴露隐性约束
普通错误信息常把真正原因折叠掉。--dry-run -v 不改任何文件,但会完整输出依赖求解过程,重点盯住含 because 的嵌套行。
例如:
Root composer.json requires monolog/monolog ^2.0 → satisfiable by monolog/monolog[2.0.0, ..., 2.10.0]. monolog/monolog 2.10.0 requires php ^7.2 || ^8.0 → your PHP version (8.1.0) does not satisfy that requirement.
这说明问题不在版本号冲突,而在 PHP 版本不兼容——而这个信息在普通 install 错误里根本看不到。
- 必须加
-v,没它就看不到because链 - 翻输出末尾 10 行,反复出现的包名(如
symfony/console)大概率是冲突枢纽 - 若发现
Root requirements段落里某行明显过时(比如还写着"laravel/framework": "^9.0"),直接改它
真正卡住你的,往往不是你主动 require 的包,而是 require-dev 里的测试工具、或者某个中间包的 conflict 声明。定位时别只看报错第一行,要顺着 why-not 输出从下往上读,再用 show --tree 和 depends -r 补全路径——否则很容易在错误的方向上反复试错。

















