{"record":{"id":"5ea9995ff2aff1c7","repo":"doctrine/orm","slug":"classmetadata-settable-has-to-be-called-before","errorCode":null,"errorMessage":"ClassMetadata::setTable() has to be called before defining a one to one relationship.","messagePattern":"ClassMetadata::setTable\\(\\) has to be called before defining a one to one relationship\\.","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"src/Mapping/ToOneOwningSideMapping.php","lineNumber":184,"sourceCode":"            }\n\n            if ($joinColumn->name[0] === '`') {\n                $joinColumn->name   = trim($joinColumn->name, '`');\n                $joinColumn->quoted = true;\n            }\n\n            if ($joinColumn->referencedColumnName[0] === '`') {\n                $joinColumn->referencedColumnName = trim($joinColumn->referencedColumnName, '`');\n                $joinColumn->quoted               = true;\n            }\n\n            $mapping->sourceToTargetKeyColumns[$joinColumn->name] = $joinColumn->referencedColumnName;\n            $mapping->joinColumnFieldNames[$joinColumn->name]     = $joinColumn->fieldName ?? $joinColumn->name;\n        }\n\n        if ($uniqueConstraintColumns) {\n            if (! $table) {\n                throw new RuntimeException('ClassMetadata::setTable() has to be called before defining a one to one relationship.');\n            }\n\n            $table['uniqueConstraints'][$mapping->fieldName . '_uniq'] = ['columns' => $uniqueConstraintColumns];\n        }\n\n        $mapping->targetToSourceKeyColumns = array_flip($mapping->sourceToTargetKeyColumns);\n\n        return $mapping;\n    }\n\n    public function offsetSet(mixed $offset, mixed $value): void\n    {\n        if ($offset === 'joinColumns') {\n            $joinColumns = [];\n            foreach ($value as $column) {\n                $joinColumns[] = JoinColumnMapping::fromMappingArray($column);\n            }\n","sourceCodeStart":166,"sourceCodeEnd":202,"githubUrl":"https://github.com/doctrine/orm/blob/d9b9ff73016bf598ae07515f97289ce8074e97a5/src/Mapping/ToOneOwningSideMapping.php#L166-L202","documentation":"When an owning one-to-one association has MULTIPLE join columns that are not the primary key, Doctrine must record a composite UNIQUE constraint on the owning table (fieldName . '_uniq'). That write needs ClassMetadata::$table to be populated already; the mapping builder throws when the one-to-one is defined before setTable(). Standard mapping drivers always set the table first, so this error is almost exclusive to programmatic metadata construction out of order.","triggerScenarios":"Calling $classMetadata->mapOneToOne(['joinColumns' => [...multiple...]]) (or mapManyToOne/joinColumn building that produces uniqueConstraintColumns) before $classMetadata->setTable()/setPrimaryTable(); custom mapping drivers or runtime metadata builders that map associations before the table.","commonSituations":"Hand-built ClassMetadata (dynamic entities, tests, migration tooling); custom mapping driver with wrong call order; code that copies mappings between ClassMetadata instances.","solutions":["Call $classMetadata->setTable(...) (set the primary table) before mapping the one-to-one association","Prefer a standard mapping driver (attributes/XML/YAML), which sets the table before associations by construction","If writing a custom driver, mirror the order used by the AttributeDriver"],"exampleFix":"// before\n$classMetadata->mapOneToOne($mapping); // composite join columns\n$classMetadata->setTable('invoice');\n\n// after\n$classMetadata->setTable('invoice');\n$classMetadata->mapOneToOne($mapping);","handlingStrategy":"validation","validationCode":"if ($classMetadata->getTableName() === null) {\n    throw new RuntimeException('Set the primary table before mapping one-to-one associations.');\n}\n$classMetadata->mapOneToOne($mapping);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Prefer standard mapping drivers over hand-built ClassMetadata","When building metadata programmatically, set the table first, then associations","Write a smoke test that builds metadata for every dynamic entity"],"tags":["orm-mapping","one-to-one","classmetadata","unique-constraint"],"backgroundTag":"orm-mapping-misconfiguration","analyzedSha":"d9b9ff73016bf598ae07515f97289ce8074e97a5","analyzedAt":"2026-08-21T06:13:15.863Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}