cakephp/cakephp · error · LogicException
` ` contains duplicate method ` ` which is already provided…
Error message
`%s` contains duplicate method `%s` which is already provided by `%s`.
What it means
BehaviorRegistry::_getMethods() throws this LogicException when a newly loaded behavior exposes a public method (proxyable via the table) whose name is already provided by another loaded behavior. CakePHP maps behavior methods onto the table, so duplicate names would be ambiguous and registration is aborted.
Solutions
- Remove one of the colliding behaviors from initialize() — the message names which class already provides the method.
- Rename the method in the offending behavior (only your own code) to a unique name.
- If overriding intentionally, subclass the provider behavior and load only the subclass.
- Check for accidental double-loading of the same behavior under two aliases (each alias counts as a provider).
- Pin plugin versions or patch vendor behavior so method names stay distinct; file an upstream rename issue.
Example fix
// before
$this->addBehavior('My.Utils'); // public function touch()
$this->addBehavior('Shadow.Shadow'); // also public function touch()
// after
$this->addBehavior('My.Utils');
// remove Shadow, or rename its method in a subclass:
class MyShadowBehavior extends ShadowBehavior { public function shadowTouch() { return $this->touch(...func_get_args()); } } Defensive patterns
Strategy: try-catch
Validate before calling
$newMethods = array_filter(get_class_methods(new SecondBehavior()), fn($m) => !str_starts_with($m, 'find'));
foreach ($table->behaviors()->loaded() as $loaded) {
$overlap = array_intersect($newMethods, get_class_methods($loaded));
if ($overlap) { /* handle collision before addBehavior */ }
} Try / catch
try {
$table->addBehavior('Shadow.Shadow');
} catch (\LogicException $e) {
if (str_contains($e->getMessage(), 'duplicate method')) {
$this->log($e->getMessage());
} else {
throw $e;
}
} Prevention
- Prefix public methods in reusable behaviors with a plugin-specific word
- Never load a behavior and its deprecated/renamed successor together on one table
- Grep for public function definitions when introducing a new behavior
- Table-level integration tests that instantiate all tables catch this at boot
- Check vendor behavior classes for shared helper names like touch/slug before combining plugins
When it happens
Trigger: $table->addBehavior('SecondBehavior') where SecondBehavior declares a public method like `slugify()` or `softDelete()` that an already-attached behavior also declares; occurs via set() or _create during initialize(), so the table cannot even be constructed.
Common situations: Two utility plugins both adding `touch()`/`moveUp()` style methods; loading both a deprecated behavior and its replacement that kept the same API; a project base AppBehavior and a plugin behavior both defining helpers with common names.
Understand the failure class
Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.
Related errors
- ` ` contains duplicate finder ` ` which is already provided…
- All primary key value(s) are needed for updating
- Argument 2 is expected to have a `repository` key that…
- Argument 2 is expected to match one of the…
- Association alias ` ` is already set.
AI-assisted analysis of cakephp/cakephp@1128eba9b0 (2026-09-12).
Data as JSON: /api/errors/126efe933f351d42.
Report an issue: GitHub.
Appendix: source
Thrown at src/ORM/BehaviorRegistry.php:202
$class,
$finder,
$duplicate[0],
);
throw new LogicException($error);
}
$finders[$finder] = [$alias, $methodName];
}
foreach ($methods as $method => $methodName) {
if (isset($this->_methodMap[$method]) && $this->has($this->_methodMap[$method][0])) {
$duplicate = $this->_methodMap[$method];
$error = sprintf(
'`%s` contains duplicate method `%s` which is already provided by `%s`.',
$class,
$method,
$duplicate[0],
);
throw new LogicException($error);
}
$methods[$method] = [$alias, $methodName];
}
return compact('methods', 'finders');
}
/**
* Set an object directly into the registry by name.
*
* @param string $name The name of the object to set in the registry.
* @param \Cake\ORM\Behavior $object instance to store in the registry
* @return $this
*/
public function set(string $name, object $object)
{
parent::set($name, $object);
View on GitHub (pinned to 1128eba9b0)