phalcon/cphalcon · error · Phalcon\Mvc\Model\Exceptions\RelationRequiresObjectOrArray

Only objects/arrays can be stored as part of has-many/has-on

Error message

Only objects/arrays can be stored as part of has-many/has-one/has-one-through/has-many-to-many relations on model {className} on Relation {relationName}

What it means

Thrown by Model::postSaveRelatedRecords() (phalcon/Mvc/Model.zep:5575): a has-one, has-many, has-one-through or has-many-to-many relation was assigned something that is neither an object nor an array. These relations accept one instance or an array/Resultset of instances because each related record is saved after the master. The exception class is Phalcon\Mvc\Model\Exceptions\RelationRequiresObjectOrArray; the implicit transaction is rolled back first.

Source

Thrown at phalcon/Mvc/Model.zep:5575

             * Try to get a relation with the same name
             */
            let relation = <RelationInterface> manager->getRelationByAlias(
                className,
                name
            );

            if typeof relation === "object" {
                /**
                 * Discard belongsTo relations
                 */
                if relation->getType() == Relation::BELONGS_TO {
                    continue;
                }

                if unlikely (typeof record !== "object" && typeof record !== "array") {
                    connection->rollback(nesting);

                    throw new RelationRequiresObjectOrArray(className, name);
                }

                let columns = relation->getFields(),
                    referencedModel = relation->getReferencedModel(),
                    referencedFields = relation->getReferencedFields();

                /**
                 * Create an implicit array for has-many/has-one records
                 */
                if typeof record === "object" {
                    let relatedRecords = [record];
                } else {
                    let relatedRecords = record;
                }

                let isThrough = (bool) relation->isThrough();

                /**

View on GitHub (pinned to b7419de9cd)

Solutions

  1. Assign an instance or an array of instances: $invoice->items = [new Item([...]), new Item([...])];
  2. To clear a has-many relation, assign an empty array or use the relation's sync/clear mechanism, not null or false
  3. Filter incoming payload keys so only scalar FK fields and known relation shapes reach the model

Example fix

// before
$invoice = new Invoice([...]);
$invoice->items = 3; // RelationRequiresObjectOrArray
$invoice->save();

// after
$invoice->items = [
    new Item(['title' => 'A'),
    new Item(['title' => 'B'),
];
$invoice->save();
Defensive patterns

Strategy: type-guard

Validate before calling

$value = $payload['items'] ?? null;
$ok = $value instanceof \Phalcon\Mvc\ModelInterface
    || (is_array($value) && array_reduce($value, fn($c, $i) => $c && $i instanceof \Phalcon\Mvc\ModelInterface, true));
if (!$ok) {
    // refuse before save(): has-one/has-many relations need instance(s)
    unset($payload['items']);
}

Type guard

function isRelationValue($value): bool
{
    if ($value instanceof \Phalcon\Mvc\ModelInterface) {
        return true;
    }
    if (!is_array($value)) {
        return false;
    }
    foreach ($value as $item) {
        if (!$item instanceof \Phalcon\Mvc\ModelInterface) {
            return false;
        }
    }
    return true;
}

Try / catch

try {
    $invoice->save();
} catch (\Phalcon\Mvc\Model\Exceptions\RelationRequiresObjectOrArray $e) {
    // relation property holds a scalar; drop it and report a validation error
    // (the implicit transaction was already rolled back by Phalcon)
    $messages = new Validation();
    // surface 'items must be a model or list of models' to the client
}

Prevention

When it happens

Trigger: Assigning scalars to relation properties before save: $invoice->items = 5, $invoice->details = 'none', or $invoice->tags = null. Also assigning nested arrays of plain values (['a','b']) instead of arrays of model objects.

Common situations: Form/request data bound blindly to the model so numeric strings end up in relation properties; partial updates that set relations to null to clear them; mixing FK assignment with relation assignment conventions.

Related errors


AI-assisted analysis of phalcon/cphalcon@b7419de9cd (2026-08-21). Data as JSON: /api/errors/046c125d81f744f8. Report an issue: GitHub.