ErrLookup › Background articles › PHP \LogicException: the programmer-error exception — missing components, conflicting options, and misconfigured services that fail loud

PHP \LogicException: the programmer-error exception — missing components, conflicting options, and misconfigured services that fail loud

PHP's \LogicException signals a fault in how code is written or configured — a missing optional dependency, mutually exclusive options, a service declared in a way the container cannot honour, or a precondition the caller skipped. Symfony, Laravel, Composer, and Guzzle all reach for it to refuse an operation outright instead of silently degrading, so when a developer meets it the fix is almost always at the call site or in configuration, not in retrying or waiting.

Distilled from 199 documented records across 4 repositories.

Background

LogicException is a built-in PHP base class for errors that represent faults in the program itself. The PHP manual frames it as the sibling of RuntimeException: where RuntimeException covers conditions that only arise at run time, LogicException covers calls that should never have been made in the current state. When a library throws it, the message is not "something transient went wrong" but "this call is wrong". Across the four repositories in this family, the posture is the same — fail loud, do not fall back, do not return a silent no-op.

The mechanism varies by layer. At the dependency-injection and container layer (heavily used by Symfony), LogicException fires during compilation or at first service resolution when an optional component is referenced but not installed — symfony/form, symfony/validator, symfony/mime, symfony/security-core, symfony/acl, or a too-old symfony/http-client — or when a service is declared in a way the container cannot honour (a synthetic service asked to reset, a non-lazy service asked to resetLazyObject). At the configuration layer it rejects mutually exclusive option combinations at construction time, so the misuse surfaces the moment a config object or attribute is built rather than pages later — for example #[MapEntity] given both id and mapping, or both id and exclude, or a messenger routing wildcard that is not a valid namespace prefix.

From the caller's side the exception usually arrives with no ambiguity about which call is at fault, because the message names the symbol, the option, or the missing class. It is distinct from a fatal "Class not found": the class was autoloaded and the code chose to refuse the operation. Composer uses LogicException to assert install-state invariants — querying a Locker before composer.lock exists, or bootstrapping a plugin whose install path resolved to null. Laravel uses it to refuse an operation a driver never implemented (dropAllTables on the base Schema\Builder) or that the data shape forbids (queueing an Eloquent\Collection whose models span more than one class, or more than one connection). Guzzle uses it as a deliberate security control: FileCookieJar::__unserialize() throws unconditionally because a deserialized jar is an object-injection gadget that could write attacker bytes to an attacker-chosen path.

A handful of records mark states the library treats as unreachable — ImportMapUpdateChecker comparing non-semver versions, GitBitbucketDriver finding no fallback driver after getRepoData() returned false, PluginManager with an empty autoload list. Reaching those usually means a subclass overrode a method it should not have, an upstream tag produced an unexpected version shape, or a genuine bug worth reporting upstream. The unifying rule across the family: do not swallow the exception, do not paper over it — fix the configuration or the call.

Common causes

What usually fixes it

Documented occurrences

…and 179 more across the corpus — use search.

Honest provenance: generated on 2026-08-12 from AI-assisted analysis of the linked records. See how records are made.