yiisoft/yii2 · error · InvalidCallException

Unsetting an unknown or read-only property: {class}::{name}

Error message

Unsetting an unknown or read-only property: {class}::{name}

What it means

Component::__unset() first tries the class itself (setter path), then asks each attached behavior via canSetProperty() and nulls the property on the first behavior that accepts it. Only when the class and every attached behavior refuse does it throw InvalidCallException('Unsetting an unknown or read-only property: C::p'). With Components the error therefore also means: no currently attached behavior provides that property.

Source

Thrown at framework/base/Component.php:292

     */
    public function __unset($name)
    {
        $setter = 'set' . $name;
        if (method_exists($this, $setter)) {
            $this->$setter(null);
            return;
        }

        // behavior property
        $this->ensureBehaviors();
        foreach ($this->_behaviors as $behavior) {
            if ($behavior->canSetProperty($name)) {
                $behavior->$name = null;
                return;
            }
        }

        throw new InvalidCallException('Unsetting an unknown or read-only property: ' . get_class($this) . '::' . $name);
    }

    /**
     * Calls the named method which is not a class method.
     *
     * This method will check if any attached behavior has
     * the named method and will execute it if available.
     *
     * Do not call this method directly as it is a PHP magic method that
     * will be implicitly called when an unknown method is being invoked.
     * @param string $name the method name
     * @param array $params method parameters
     * @return mixed the method return value
     * @throws UnknownMethodException when calling unknown method
     */
    public function __call($name, $params)
    {
        $this->ensureBehaviors();

View on GitHub (pinned to 66f00d18a2)

Solutions

  1. Inspect live behaviors with $model->getBehaviors() and compare with the intended behaviors() config; a missing behavior is the usual answer
  2. Use the class's explicit clearing API instead of unset()
  3. Add a setter on the component or on the behavior if null-clearing is a legitimate operation

Example fix

// before
$post = clone $basePost; // Component::__clone detaches behaviors
unset($post->slug); // slug came from SlugBehavior => throws

// after
$post->attachBehavior('slug', \app\behaviors\SlugBehavior::class);
unset($post->slug); // behavior now accepts the unset
Defensive patterns

Strategy: validation

Validate before calling

if ($component->canSetProperty($name)) { // Component::canSetProperty also checks attached behaviors
    unset($component->$name);
}

Prevention

When it happens

Trigger: unset($model->someProp) where someProp was expected from a behavior that is not attached - typo in behaviors(), a conditional behavior disabled in the current scenario, or behaviors cleared by clone (Component::__clone resets them); cleanup loops unsetting dynamic properties before caching.

Common situations: Behavior-driven models whose behaviors() config drifted; cloned components later treated as if their behaviors survived the clone.

Related errors


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