Skip to content
Latchkey

Composer "replace"/"provide" Conflict - Phantom or Duplicate Packages

A replace entry tells Composer a package is already provided (so it should not be installed separately), and provide declares a virtual capability is satisfied. When these are set wrong - a stale replace, or a provide with no real implementation - resolution either omits a package you need or cannot find a concrete provider.

What this error means

Composer resolves to a set that is missing a package you expected (because something replaces it), or fails to resolve a virtual requirement that only has provide declarations and no real implementation. The class/function from the "replaced" package is absent at runtime.

composer.json + PHP error
// a monorepo package replaces a split package it no longer ships
"replace": { "acme/logger": "*" }

# Composer therefore never installs acme/logger, but app code still uses it:
PHP Fatal error: Uncaught Error: Class "Acme\Logger\Logger" not found

Common causes

A stale or wildcard replace hides a real package

"replace": { "acme/logger": "*" } claims this package supplies acme/logger, so Composer skips installing the real one. If it no longer actually ships those classes, they vanish.

A provide with no concrete implementation

A provide for a virtual package (e.g. psr/log-implementation) satisfies a requirement on paper. If nothing real implements it, code that resolves the implementation at runtime fails.

How to fix it

Find what replaces or provides the missing package

Ask Composer why a package is absent or how a virtual requirement is satisfied.

Terminal
composer why-not acme/logger
composer depends acme/logger
composer show --tree | grep -i logger

Remove the stale replace entry

If a replace no longer reflects reality, drop it so Composer installs the real package again.

composer.json
{
  "replace": {}
}

Require a concrete implementation for a virtual package

When a provide is virtual, also require something that really implements it.

Terminal
composer require monolog/monolog   # real psr/log implementation

How to prevent it

  • Use replace only for code you actually bundle; avoid wildcard versions.
  • Pair every virtual provide with a real implementing dependency.
  • Run composer show --tree to verify the resolved set contains what you expect.

Related guides

Tired of flaky CI? Latchkey auto-heals failed jobs and retries them for you. Start free →