{"record":{"id":"61220854f6e2f3da","repo":"yiisoft/yii2","slug":"unsetting-an-unknown-or-read-only-property-class","errorCode":null,"errorMessage":"Unsetting an unknown or read-only property: {class}::{name}","messagePattern":"Unsetting an unknown or read-only property: (.+?)::(.+?)","errorType":"exception","errorClass":"InvalidCallException","httpStatus":null,"severity":"error","filePath":"framework/base/Component.php","lineNumber":292,"sourceCode":"     */\n    public function __unset($name)\n    {\n        $setter = 'set' . $name;\n        if (method_exists($this, $setter)) {\n            $this->$setter(null);\n            return;\n        }\n\n        // behavior property\n        $this->ensureBehaviors();\n        foreach ($this->_behaviors as $behavior) {\n            if ($behavior->canSetProperty($name)) {\n                $behavior->$name = null;\n                return;\n            }\n        }\n\n        throw new InvalidCallException('Unsetting an unknown or read-only property: ' . get_class($this) . '::' . $name);\n    }\n\n    /**\n     * Calls the named method which is not a class method.\n     *\n     * This method will check if any attached behavior has\n     * the named method and will execute it if available.\n     *\n     * Do not call this method directly as it is a PHP magic method that\n     * will be implicitly called when an unknown method is being invoked.\n     * @param string $name the method name\n     * @param array $params method parameters\n     * @return mixed the method return value\n     * @throws UnknownMethodException when calling unknown method\n     */\n    public function __call($name, $params)\n    {\n        $this->ensureBehaviors();","sourceCodeStart":274,"sourceCodeEnd":310,"githubUrl":"https://github.com/yiisoft/yii2/blob/66f00d18a29b520f85e8e8f1e32d1e7e7b556cac/framework/base/Component.php#L274-L310","documentation":"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.","triggerScenarios":"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.","commonSituations":"Behavior-driven models whose behaviors() config drifted; cloned components later treated as if their behaviors survived the clone.","solutions":["Inspect live behaviors with $model->getBehaviors() and compare with the intended behaviors() config; a missing behavior is the usual answer","Use the class's explicit clearing API instead of unset()","Add a setter on the component or on the behavior if null-clearing is a legitimate operation"],"exampleFix":"// before\n$post = clone $basePost; // Component::__clone detaches behaviors\nunset($post->slug); // slug came from SlugBehavior => throws\n\n// after\n$post->attachBehavior('slug', \\app\\behaviors\\SlugBehavior::class);\nunset($post->slug); // behavior now accepts the unset","handlingStrategy":"validation","validationCode":"if ($component->canSetProperty($name)) { // Component::canSetProperty also checks attached behaviors\n    unset($component->$name);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Re-attach required behaviors after clone, or override __clone() to reattach them","Keep behavior config declarative in behaviors() instead of runtime attach calls","Prefer explicit clearing methods over unset() on behavior-provided properties"],"tags":["oop","behaviors","magic-methods","unset"],"backgroundTag":"readonly-property-unset","analyzedSha":"66f00d18a29b520f85e8e8f1e32d1e7e7b556cac","analyzedAt":"2026-08-17T05:17:23.470Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}