| name | ci-matrix-troubleshooting |
| description | Use when CI matrix has gone red and needs diagnosis. Activates: ci matrix fail, matrix red, prefer-lowest fail, prefer-stable fail, dependency conflict, composer resolve, version excluded, security-advisories floor, testbench phpunit interlock, matrix cell regression; mentions: a specific cell failing in GitHub Actions. |
CI Matrix Troubleshooting
Use this skill when a matrix cell has already failed. For preventive
work โ writing code that'll survive the full range โ activate
cross-version-laravel-support instead.
Reproduce locally first
Before reading CI logs in detail, reproduce the failing cell's
resolution locally. Most matrix failures are resolver differences,
not code bugs. Run the three-step verification from
cross-version-laravel-support โ Local verification workflow
(default / --prefer-lowest / --prefer-stable).
If the cell pins a specific PHP version, switch shells with
phpenv / asdf / Docker before running.
Usual suspects
Failures cluster around a handful of patterns. Check in order โ
cheap diagnostics first.
1. A transitive dep bumped its floor
Common culprit: roave/security-advisories tightens a PHPUnit /
Guzzle / etc. floor in a new release, and prefer-lowest in the
package pulls the now-incompatible combination.
Diagnose with composer why-not:
composer why-not phpunit/phpunit 11.0
Fix: widen the package's constraint to match the advisory's floor,
or add a conflict entry that excludes the advisory's bad range.
2. Testbench โ PHPUnit interlock
Testbench pins PHPUnit constraints per major. prefer-lowest can
land on a Testbench version whose PHPUnit range the matrix cell
can't reach (e.g. the cell's Laravel column needs Testbench 9,
which requires PHPUnit 10+, but another cell pins 9.x).
Fix: tighten the orchestra/testbench floor in require-dev to
exclude the incompatible version.
3. The package's own require floor is wrong
The declared minimum doesn't actually install with its dependencies
at the floor version. Happens when a code path uses a method added
in a minor release above the declared floor.
Diagnose: prefer-lowest fails with "method X does not exist" or
"class Y not found". Check the upstream CHANGELOG for when the
symbol appeared.
Fix: bump the package's own floor to the version where the symbol
landed. Document in the release notes.
4. phpstan / larastan floor incompatible with older Laravel
Static-analysis tooling often drops support for older frameworks
before runtime packages do. A prefer-lowest run with Laravel 11
and larastan's latest may fail static analysis without any runtime
issue.
Fix: pin larastan/larastan to the last version that supports the
package's Laravel floor, or exclude static analysis from the
prefer-lowest cells (not both โ document the trade-off).
5. Blade directive / trait / facade available on only one side
Added code uses an API that doesn't exist on the floor. Covered
by the cross-version-laravel-support skill โ diagnostic pattern
here is the same:
composer update --prefer-lowest
Fix: guard the call site or raise the floor.
Second-step diagnostics
If prefer-lowest reproduction doesn't surface the issue, zoom in
with composer why / why-not:
composer why vendor/package
composer why-not vendor/package 2.0.0
For resolver conflicts that span multiple packages, composer update vendor/package --with-dependencies --dry-run shows what
would move without committing.
Fix patterns
Pick the narrowest fix that keeps the supported range honest:
- Widen a constraint โ usually a transitive dep bump caught
us off guard. Safe if the new range is a superset.
- Raise the package's floor โ if the feature is genuinely
required, declare it. Bump to a minor version in the next
release and note the minimum change.
- Exclude a matrix cell โ last resort. Adds justification in
.github/workflows/run-tests.yml (comment on the excluded
cell), open a tracking issue.
conflict directive โ when a security advisory's floor is
too aggressive for the supported range; excludes the bad
version window.
When to file upstream
Distinguish:
- Our constraint is wrong โ fix locally, don't bother the
dependency maintainer.
- Dependency ships an over-eager floor โ file an upstream
issue with: reproduction steps (composer command + output), the
version window that's too narrow, and why your constraint range
is correct.
A useful bug report on the offender saves other consumers the
same diagnostic trip.