yiisoft/yii2 · error · InvalidCallException

Unsetting read-only property: {class}::{name}

Error message

Unsetting read-only property: {class}::{name}

What it means

unset() on an inaccessible property triggers BaseObject::__unset(): if a setter exists it is called with null; if only a getter exists the property is read-only and InvalidCallException('Unsetting read-only property: C::p') is thrown. Note that for completely unknown names __unset() does nothing silently - only the read-only case throws, so this error always means a getter-only property met an unset().

Source

Thrown at framework/base/BaseObject.php:207

    /**
     * Sets an object property to null.
     *
     * Do not call this method directly as it is a PHP magic method that
     * will be implicitly called when executing `unset($object->property)`.
     *
     * Note that if the property is not defined, this method will do nothing.
     * If the property is read-only, it will throw an exception.
     * @param string $name the property name
     * @throws InvalidCallException if the property is read only.
     * @see https://www.php.net/manual/en/function.unset.php
     */
    public function __unset($name)
    {
        $setter = 'set' . $name;
        if (method_exists($this, $setter)) {
            $this->$setter(null);
        } elseif (method_exists($this, 'get' . $name)) {
            throw new InvalidCallException('Unsetting read-only property: ' . get_class($this) . '::' . $name);
        }
    }

    /**
     * Calls the named method which is not a class method.
     *
     * 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
     * @throws UnknownMethodException when calling unknown method
     * @return mixed the method return value
     */
    public function __call($name, $params)
    {
        throw new UnknownMethodException('Calling unknown method: ' . get_class($this) . "::$name()");
    }

View on GitHub (pinned to 66f00d18a2)

Solutions

  1. Call the class's own clearing method, or clear via a setter instead of unset()
  2. Add a setter if setting null is a meaningful operation for the class
  3. Skip the unset when !$object->canSetProperty($name)

Example fix

// before
unset($report->generatedAt); // getter only => InvalidCallException

// after
$report->clearGeneratedAt(); // explicit class method, or add setGeneratedAt(null) support
Defensive patterns

Strategy: validation

Validate before calling

if ($object->canSetProperty($name)) {
    unset($object->$name); // routes through the setter with null
}
// read-only properties are left untouched - no exception

Prevention

When it happens

Trigger: unset($report->generatedAt) where only getGeneratedAt() exists; generic cleanup code that unsets fields before caching or serializing an object; array-hygiene routines (where unset is always safe) reused on objects with computed getters.

Common situations: Serialization slimming that strips computed getters before var_export/json_encode; refactors from array payloads to objects that kept the old unset() calls.

Related errors


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