{"record":{"id":"73f0b319f1d3606b","repo":"phalcon/cphalcon","slug":"only-objects-can-be-stored-as-part-of-belongs-to-r","errorCode":null,"errorMessage":"Only objects can be stored as part of belongs-to relations in '{className}' Relation {relationName}","messagePattern":"Only objects can be stored as part of belongs-to relations in '(.+?)' Relation (.+?)","errorType":"exception","errorClass":"Phalcon\\Mvc\\Model\\Exceptions\\BelongsToRequiresObject","httpStatus":null,"severity":"error","filePath":"phalcon/Mvc/Model.zep","lineNumber":5468,"sourceCode":"            let relation = <RelationInterface> manager->getRelationByAlias(\n                className,\n                name\n            );\n\n            if typeof relation === \"object\" {\n                /**\n                 * Get the relation type\n                 */\n                let type = relation->getType();\n\n                /**\n                 * Only belongsTo are stored before save the master record\n                 */\n                if type == Relation::BELONGS_TO {\n                    if unlikely typeof record !== \"object\" {\n                        connection->rollback(nesting);\n\n                        throw new BelongsToRequiresObject(get_class(this), name);\n                    }\n\n                    /**\n                     * If dynamic update is enabled, saving the record must not take any action.\n                     * Recursion through circular relations is prevented by the visited\n                     * collection inside doSave().\n                     */\n                    if !record->doSave(visited) {\n                        /**\n                         * Get the validation messages generated by the\n                         * referenced model\n                         */\n                        this->appendMessagesFrom(record);\n\n                        /**\n                         * Rollback the implicit transaction\n                         */\n                        connection->rollback(nesting);","sourceCodeStart":5450,"sourceCodeEnd":5486,"githubUrl":"https://github.com/phalcon/cphalcon/blob/b7419de9cd0a8a3f48441ead84c9f8415d463e25/phalcon/Mvc/Model.zep#L5450-L5486","documentation":"Thrown by Model::preSaveRelatedRecords() (phalcon/Mvc/Model.zep:5468): a belongs-to relation was assigned a non-object value. BelongsTo relations hold exactly one referenced model instance, and its primary key is copied into the local FK after the related record is saved, so only objects are accepted. The exception class is Phalcon\\Mvc\\Model\\Exceptions\\BelongsToRequiresObject; the implicit transaction is rolled back first.","triggerScenarios":"Assigning a scalar to a belongsTo relation property and saving: $invoice->customer = 123; $invoice->save(). Also assigning an array, a stdClass, or null where a Model instance is required.","commonSituations":"Confusing FK column assignment ($invoice->customerId = 123) with relation assignment ($invoice->customer = 123); API payloads hydrated directly into relation properties; refactoring from raw FK properties to relations without updating setters.","solutions":["Assign a model instance: $invoice->customer = Customer::findFirst(123);","If you only have the key, set the FK column directly instead of the relation property","For create-from-scratch flows, build the related model first: $invoice->customer = new Customer([...]);"],"exampleFix":"// before\n$invoice = new Invoice([...]);\n$invoice->customer = 123; // BelongsToRequiresObject\n$invoice->save();\n\n// after\n$invoice->customer = Customer::findFirst(123);\n// or set the FK directly:\n$invoice->customerId = 123;\n$invoice->save();","handlingStrategy":"type-guard","validationCode":"if (isset($invoice->customer) && !$invoice->customer instanceof \\Phalcon\\Mvc\\ModelInterface) {\n    // belongsTo relation must hold a model instance before save()\n    $invoice->customer = Customer::findFirst((int) $invoice->customer);\n}","typeGuard":"function isModelInstance($value): bool\n{\n    return $value instanceof \\Phalcon\\Mvc\\ModelInterface;\n}\n\n// before save:\nif (null !== $invoice->customer && !isModelInstance($invoice->customer)) {\n    throw new InvalidArgumentException('customer relation expects a Model instance');\n}","tryCatchPattern":"try {\n    $invoice->save();\n} catch (\\Phalcon\\Mvc\\Model\\Exceptions\\BelongsToRequiresObject $e) {\n    // relation property holds a scalar; set the FK column instead\n    $relationName = 'customer'; // parse from message tail\n    $invoice->{$relationName . 'Id'} = $scalarId;\n    $invoice->save();\n}","preventionTips":["Convention: assign FK columns for keys, relation properties for instances; never mix","Whitelist and cast request data before assigning to relation properties","Unit-test each relation property with an instance to lock the contract"],"tags":["phalcon","orm","relations","belongs-to","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"}