cakephp/cakephp · error · InvalidParameterException
missing_dependency
Error message
missing_dependency
What it means
InvalidParameterException with template 'missing_dependency' is thrown by ControllerFactory::getActionArgs() when an action method's parameter is type-hinted to a class/interface that the service container cannot resolve and the parameter has no default value. CakePHP refuses to call the action with a null for a required class dependency.
Solutions
- Register the dependency in the DI container (Application::services() add/bind the class or interface)
- Add a default value to the action parameter if it is optional: myAction(?MyService $service = null)
- Verify the type-hint's fully-qualified class name/import is correct
- If it should be a request scalar, change the hint to a scalar type (string/int) so it resolves from route/passed params
Example fix
// before
class ServicesController
{
public function index(PaymentGateway $gateway) { ... } // not registered
}
// after: in Application::services()
$container->add(PaymentGatewayInterface::class, StripeGateway::class);
// or give the parameter a default
public function index(?PaymentGateway $gateway = null) { ... } Defensive patterns
Strategy: try-catch
Validate before calling
use Cake\Core\Container;
// ensure the dependency is resolvable before dispatch
if (!$container->has(MyService::class)) {
$container->add(MyService::class);
} Type guard
function resolvable(Cake\Core\ContainerInterface $c, string $type): bool
{
return class_exists($type) || interface_exists($type) ? $c->has($type) : false;
} Try / catch
try {
$args = $factory->getActionArgs($reflection, $request);
} catch (Cake\Controller\Exception\InvalidParameterException $e) {
if ($e->getMessage() === 'missing_dependency') {
error_log('Unregistered DI dependency: ' . $e->getAttribute('parameter'));
}
return new Cake\Http\Response(['status' => 500]);
} Prevention
- Register every class/interface injected into controller actions in Application::services()
- Use interface bindings so implementation swaps don't break resolution
- Add a smoke test that dispatches each action to catch unresolvable hints
- Keep imports/FQCNs of type-hints correct after refactors
When it happens
Trigger: An action signature like myAction(MyService $service) where MyService is not registered/bound in the DI container; requesting positional-argument resolution for a class-typed parameter that has no default value and no matching container binding.
Common situations: Adding a new injected dependency to an action without registering it with the Application's services; typo in the type-hint namespace; interface binding missing after a refactor.
Understand the failure class
Background: "not installed", "pip install", "required for": how missing-dependency errors surface across open-source libraries — this error's family across 34 libraries.
Related errors
- Container not set.
- Flash message missing.
- Missing action
- Service provider must implement
- The property `$provides` should contain a list with service…
AI-assisted analysis of cakephp/cakephp@1128eba9b0 (2026-09-12).
Data as JSON: /api/errors/e6d0433140db2e96.
Report an issue: GitHub.
Appendix: source
Thrown at src/Controller/ControllerFactory.php:221
$resolved[] = $this->container->get($typeName);
continue;
}
// Use passedParams as a source of typed dependencies.
// The accepted types for passedParams was never defined and userland code relies on that.
if ($passedParams && $passedParams[0] instanceof $typeName) {
$resolved[] = array_shift($passedParams);
continue;
}
// Add default value if provided
// Do not allow positional arguments for classes
if ($parameter->isDefaultValueAvailable()) {
$resolved[] = $parameter->getDefaultValue();
continue;
}
throw new InvalidParameterException([
'template' => 'missing_dependency',
'parameter' => $parameter->getName(),
'type' => $typeName,
'controller' => $this->controller->getName(),
'action' => $this->controller->getRequest()->getParam('action'),
'prefix' => $this->controller->getRequest()->getParam('prefix'),
'plugin' => $this->controller->getRequest()->getParam('plugin'),
]);
}
// Use any passed params as positional arguments
if ($passedParams) {
$argument = array_shift($passedParams);
if (is_string($argument) && $type instanceof ReflectionNamedType) {
$typedArgument = $this->coerceStringToType($argument, $type);
if ($typedArgument === null) {
throw new InvalidParameterException([View on GitHub (pinned to 1128eba9b0)