yiisoft/yii2 · error · InvalidConfigException

get_class($this) . ' must define a "run()" method.'

Error message

get_class($this) . ' must define a "run()" method.'

What it means

Standalone actions (classes extending yii\base\Action, registered in a controller's actions() map) are executed via runWithParams(): it first checks method_exists($this, 'run') and throws InvalidConfigException(get_class($this) . ' must define a "run()" method.') before parameter binding, beforeRun()/afterRun(), and events. An Action without run() is unusable, so the throw fires on the first request to that action.

Solutions

  1. Add 'public function run()' to the class named in the exception message and return the response/result from it
  2. If the class is a shared base, mark it abstract and implement run() in each concrete subclass - never register the base class in actions()
  3. If you actually wanted an inline action, delete the class and add action<Id>() to the controller instead

Example fix

// before
class DownloadAction extends \yii\base\Action
{
    public function execute() { /* ... */ } // wrong method name
}

// after
class DownloadAction extends \yii\base\Action
{
    public function run()
    {
        return $this->controller->response->sendFile($this->path);
    }
}
Defensive patterns

Strategy: validation

Validate before calling

foreach ($this->actions() as $id => $definition) {
    $class = is_array($definition) ? ($definition['class'] ?? null) : $definition;
    if (is_string($class) && !method_exists($class, 'run')) {
        throw new \LogicException("Action '{$class}' registered as '{$id}' has no run() method");
    }
}

Try / catch

try {
    return $action->runWithParams($params);
} catch (\yii\base\InvalidConfigException $e) {
    Yii::error($e->getMessage());
    throw $e;
}

Prevention

When it happens

Trigger: A custom action class listed in actions() whose logic method is named execute() or handle() instead of run(); an abstract base Action class mistakenly registered directly in actions(); renaming run() during a refactor of a previously working action.

Common situations: Action classes ported from other frameworks (Symfony uses execute()); vendor Action base classes whose run() was removed and subclasses are expected to add it; scaffolding that generated an empty action body.

Understand the failure class

Background: "NotImplementedError: Subclasses should override this method" / "must be implemented" — abstract method errors explained — this error's family across 40 libraries.

Related errors


AI-assisted analysis of yiisoft/yii2@66f00d18a2 (2026-08-17). Data as JSON: /api/errors/bd473aa1e79f8bd0. Report an issue: GitHub.

Appendix: source

Thrown at framework/base/Action.php:88

     * @return string the unique ID of this action among the whole application.
     */
    public function getUniqueId()
    {
        return $this->controller->getUniqueId() . '/' . $this->id;
    }

    /**
     * Runs this action with the specified parameters.
     * This method is mainly invoked by the controller.
     *
     * @param array $params the parameters to be bound to the action's run() method.
     * @return mixed the result of the action
     * @throws InvalidConfigException if the action class does not have a run() method
     */
    public function runWithParams($params)
    {
        if (!method_exists($this, 'run')) {
            throw new InvalidConfigException(get_class($this) . ' must define a "run()" method.');
        }
        $args = $this->controller->bindActionParams($this, $params);
        Yii::debug('Running action: ' . get_class($this) . '::run(), invoked by ' . get_class($this->controller), __METHOD__);
        if (Yii::$app->requestedParams === null) {
            Yii::$app->requestedParams = $args;
        }
        if ($this->beforeRun()) {
            $result = call_user_func_array([$this, 'run'], $args);
            $this->afterRun();

            return $result;
        }

        return null;
    }

    /**
     * This method is called right before `run()` is executed.

View on GitHub (pinned to 66f00d18a2)