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

  1. Register the dependency in the DI container (Application::services() add/bind the class or interface)
  2. Add a default value to the action parameter if it is optional: myAction(?MyService $service = null)
  3. Verify the type-hint's fully-qualified class name/import is correct
  4. 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

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


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)