yiisoft/yii2 · error · InvalidArgumentException

Unknown scenario: $scenario

Error message

Unknown scenario: $scenario

What it means

Thrown by yii\base\Model::validate() after beforeValidate() but before any validator executes: the method fetches the scenarios() map (built from the 'on' keys of rules(), always containing the implicit 'default' scenario) and requires the active scenario from getScenario() to be one of its keys. An unknown name means no attribute list exists for it, so the model refuses to validate at all.

Source

Thrown at framework/base/Model.php:374

     * the applicable validation rules should be validated.
     * @param bool $clearErrors whether to call [[clearErrors()]] before performing validation
     * @return bool whether the validation is successful without any error.
     * @throws InvalidArgumentException if the current scenario is unknown.
     */
    public function validate($attributeNames = null, $clearErrors = true)
    {
        if ($clearErrors) {
            $this->clearErrors();
        }

        if (!$this->beforeValidate()) {
            return false;
        }

        $scenarios = $this->scenarios();
        $scenario = $this->getScenario();
        if (!isset($scenarios[$scenario])) {
            throw new InvalidArgumentException("Unknown scenario: $scenario");
        }

        if ($attributeNames === null) {
            $attributeNames = $this->activeAttributes();
        }

        $attributeNames = (array)$attributeNames;

        foreach ($this->getActiveValidators() as $validator) {
            $validator->validateAttributes($this, $attributeNames);
        }
        $this->afterValidate();

        return !$this->hasErrors();
    }

    /**
     * This method is invoked before validation starts.

View on GitHub (pinned to 66f00d18a2)

Solutions

  1. Declare the scenario in at least one rule: [['email'], 'required', 'on' => [self::SCENARIO_UPDATE]], or override scenarios() explicitly
  2. Fix the exact spelling and case of the string passed to setScenario() against scenarios() keys
  3. Fall back to the default scenario for dynamic names: if (!isset($model->scenarios()[$name])) { $model->scenario = Model::SCENARIO_DEFAULT; }
  4. Keep scenario names in class constants on the model and reference the constants everywhere instead of string literals

Example fix

// before
$model->scenario = 'signupp'; // typo
$model->validate(); // InvalidArgumentException: Unknown scenario: signupp

// after
class User extends \yii\base\Model
{
    const SCENARIO_SIGNUP = 'signup';
    public function rules()
    {
        return [
            [['email', 'password'], 'required', 'on' => [self::SCENARIO_SIGNUP]],
        ];
    }
}

$model->scenario = User::SCENARIO_SIGNUP;
$model->validate();
Defensive patterns

Strategy: validation

Validate before calling

$scenarios = $model->scenarios();
if (!isset($scenarios[$name])) {
    throw new \InvalidArgumentException(
        "Scenario '$name' is not declared on " . get_class($model) . '. Known: ' . implode(', ', array_keys($scenarios))
    );
}
$model->setScenario($name);

Type guard

function scenarioExists(\yii\base\Model $model, string $scenario): bool
{
    return isset($model->scenarios()[$scenario]);
}

Try / catch

try {
    $model->validate();
} catch (\InvalidArgumentException $e) {
    // scenario never declared in rules()/scenarios() — log the model class and requested scenario
    \Yii::error($e->getMessage(), __METHOD__);
}

Prevention

When it happens

Trigger: Calling $model->setScenario('update')->validate() when no rule in rules() carries 'on' => ['update']; a typo or case mismatch ('Signup' vs 'signup', names are case-sensitive); renaming/removing an 'on' clause while callers still set the old scenario; overriding rules() to return [] which leaves scenarios() with only 'default'.

Common situations: Adding a second form (login vs signup vs update) over one model and forgetting the 'on' key; scenario names set from request or config data that drift from the rules; copying scenario strings between layers where one side was refactored; calling validate() on a model whose rules only use 'except', which does not create scenarios.

Related errors


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