cakephp/cakephp · error · RuntimeException
Controller must be set first.
Error message
Controller must be set first.
What it means
ComponentRegistry::getController() is a typed accessor that throws RuntimeException when the registry's controller has never been assigned via setController(). Components are created against a controller, so using the registry before that wiring is a programming-order bug.
Solutions
- Ensure setController() is called before any code reads getController()
- Only access the controller in Component::initialize()/later lifecycle hooks, not in the constructor
- If using the registry standalone, inject a controller instance first
- In tests, construct the Controller and call setController() before creating components
Example fix
// before $registry = new ComponentRegistry(); $registry->getController(); // throws // after $controller = new ArticlesController($request, $response); $registry = new ComponentRegistry($controller); $registry->getController();
Defensive patterns
Strategy: type-guard
Validate before calling
if ($registry->getController() === null) { /* older API */ }
// prefer checking before use in component initialize():
if (!$this->getController()) { return; } Type guard
function hasController(ComponentRegistry $r): bool {
try { $r->getController(); return true; } catch (\RuntimeException $e) { return false; }
} Try / catch
try {
$controller = $registry->getController();
} catch (\RuntimeException $e) {
return; // not in a controller context (shell/test)
} Prevention
- Access the controller only in initialize() or later lifecycle hooks
- Never touch the registry from component constructors
- In standalone usage, always call setController() immediately after construction
When it happens
Trigger: Accessing getController() from a component or registry consumer during construction/bootstrap before setController() was called, or using a ComponentRegistry created manually without a controller.
Common situations: Using components outside a controller context (shell/console, tests instantiating ComponentRegistry directly), event handlers firing before the controller is attached.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Cannot auto-wire parameter $
- Missing component
- Argument ` ` must be an alphanumeric string
- Cannot apply ` ` middleware or middleware group. Use…
- Cannot convert a resource value to JSON
AI-assisted analysis of cakephp/cakephp@1128eba9b0 (2026-09-12).
Data as JSON: /api/errors/40b212c2fc806ae7.
Report an issue: GitHub.
Appendix: source
Thrown at src/Controller/ComponentRegistry.php:101
* @return $this
*/
public function setController(Controller $controller)
{
$this->_Controller = $controller;
$this->setEventManager($controller->getEventManager());
return $this;
}
/**
* Get the controller associated with the collection.
*
* @return \Cake\Controller\Controller Controller instance.
*/
public function getController(): Controller
{
if ($this->_Controller === null) {
throw new RuntimeException('Controller must be set first.');
}
return $this->_Controller;
}
/**
* Resolve a component classname.
*
* Part of the template method for {@link \Cake\Core\ObjectRegistry::load()}.
*
* @param string $class Partial classname to resolve.
* @return class-string<\Cake\Controller\Component>|null Either the correct class name or null.
*/
protected function _resolveClassName(string $class): ?string
{
/** @var class-string<\Cake\Controller\Component>|null */
return App::className($class, 'Controller/Component', 'Component');
}View on GitHub (pinned to 1128eba9b0)