{"record":{"id":"046c125d81f744f8","repo":"phalcon/cphalcon","slug":"only-objects-arrays-can-be-stored-as-part-of-has-m","errorCode":null,"errorMessage":"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}","messagePattern":"Only objects/arrays can be stored as part of has-many/has-one/has-one-through/has-many-to-many relations on model (.+?) on Relation (.+?)","errorType":"exception","errorClass":"Phalcon\\Mvc\\Model\\Exceptions\\RelationRequiresObjectOrArray","httpStatus":null,"severity":"error","filePath":"phalcon/Mvc/Model.zep","lineNumber":5575,"sourceCode":"             * Try to get a relation with the same name\n             */\n            let relation = <RelationInterface> manager->getRelationByAlias(\n                className,\n                name\n            );\n\n            if typeof relation === \"object\" {\n                /**\n                 * Discard belongsTo relations\n                 */\n                if relation->getType() == Relation::BELONGS_TO {\n                    continue;\n                }\n\n                if unlikely (typeof record !== \"object\" && typeof record !== \"array\") {\n                    connection->rollback(nesting);\n\n                    throw new RelationRequiresObjectOrArray(className, name);\n                }\n\n                let columns = relation->getFields(),\n                    referencedModel = relation->getReferencedModel(),\n                    referencedFields = relation->getReferencedFields();\n\n                /**\n                 * Create an implicit array for has-many/has-one records\n                 */\n                if typeof record === \"object\" {\n                    let relatedRecords = [record];\n                } else {\n                    let relatedRecords = record;\n                }\n\n                let isThrough = (bool) relation->isThrough();\n\n                /**","sourceCodeStart":5557,"sourceCodeEnd":5593,"githubUrl":"https://github.com/phalcon/cphalcon/blob/b7419de9cd0a8a3f48441ead84c9f8415d463e25/phalcon/Mvc/Model.zep#L5557-L5593","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Assign an instance or an array of instances: $invoice->items = [new Item([...]), new Item([...])];","To clear a has-many relation, assign an empty array or use the relation's sync/clear mechanism, not null or false","Filter incoming payload keys so only scalar FK fields and known relation shapes reach the model"],"exampleFix":"// before\n$invoice = new Invoice([...]);\n$invoice->items = 3; // RelationRequiresObjectOrArray\n$invoice->save();\n\n// after\n$invoice->items = [\n    new Item(['title' => 'A'),\n    new Item(['title' => 'B'),\n];\n$invoice->save();","handlingStrategy":"type-guard","validationCode":"$value = $payload['items'] ?? null;\n$ok = $value instanceof \\Phalcon\\Mvc\\ModelInterface\n    || (is_array($value) && array_reduce($value, fn($c, $i) => $c && $i instanceof \\Phalcon\\Mvc\\ModelInterface, true));\nif (!$ok) {\n    // refuse before save(): has-one/has-many relations need instance(s)\n    unset($payload['items']);\n}","typeGuard":"function isRelationValue($value): bool\n{\n    if ($value instanceof \\Phalcon\\Mvc\\ModelInterface) {\n        return true;\n    }\n    if (!is_array($value)) {\n        return false;\n    }\n    foreach ($value as $item) {\n        if (!$item instanceof \\Phalcon\\Mvc\\ModelInterface) {\n            return false;\n        }\n    }\n    return true;\n}","tryCatchPattern":"try {\n    $invoice->save();\n} catch (\\Phalcon\\Mvc\\Model\\Exceptions\\RelationRequiresObjectOrArray $e) {\n    // relation property holds a scalar; drop it and report a validation error\n    // (the implicit transaction was already rolled back by Phalcon)\n    $messages = new Validation();\n    // surface 'items must be a model or list of models' to the client\n}","preventionTips":["Bind request data to explicit model fields; never pass raw arrays to relation properties","To clear a has-many relation assign [] (empty array), not null or false","Validate relation payloads with the type guard above before save()"],"tags":["phalcon","orm","relations","has-many","has-one","type-mismatch"],"backgroundTag":"orm-relation-type-mismatch","analyzedSha":"b7419de9cd0a8a3f48441ead84c9f8415d463e25","analyzedAt":"2026-08-21T06:21:18.811Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}