{"record":{"id":"2db14fbe88dbc0e2","repo":"yiisoft/yii2","slug":"class-does-not-have-a-primary-key-you-should-ei","errorCode":null,"errorMessage":"{class} does not have a primary key. You should either define a primary key for the corresponding table or override the primaryKey() method.","messagePattern":"(.+?) does not have a primary key\\. You should either define a primary key for the corresponding table or override the primaryKey\\(\\) method\\.","errorType":"exception","errorClass":"yii\\db\\Exception","httpStatus":null,"severity":"critical","filePath":"framework/db/BaseActiveRecord.php","lineNumber":1171,"sourceCode":"\n    /**\n     * Returns the old primary key value(s).\n     * This refers to the primary key value that is populated into the record\n     * after executing a find method (e.g. find(), findOne()).\n     * The value remains unchanged even if the primary key attribute is manually assigned with a different value.\n     * @param bool $asArray whether to return the primary key value as an array. If `true`,\n     * the return value will be an array with column name as key and column value as value.\n     * If this is `false` (default), a scalar value will be returned for non-composite primary key.\n     * @return mixed the old primary key value. An array (column name => column value) is returned if the primary key\n     * is composite or `$asArray` is `true`. A string is returned otherwise (null will be returned if\n     * the key value is null).\n     * @throws Exception if the AR model does not have a primary key\n     */\n    public function getOldPrimaryKey($asArray = false)\n    {\n        $keys = static::primaryKey();\n        if (empty($keys)) {\n            throw new Exception(get_class($this) . ' does not have a primary key. You should either define a primary key for the corresponding table or override the primaryKey() method.');\n        }\n        if (!$asArray && count($keys) === 1) {\n            return isset($this->_oldAttributes[$keys[0]]) ? $this->_oldAttributes[$keys[0]] : null;\n        }\n\n        $values = [];\n        foreach ($keys as $name) {\n            $values[$name] = isset($this->_oldAttributes[$name]) ? $this->_oldAttributes[$name] : null;\n        }\n\n        return $values;\n    }\n\n    /**\n     * Populates an active record object using a row of data from the database/storage.\n     *\n     * This is an internal method meant to be called to create active record objects after\n     * fetching data from the database. It is mainly used by [[ActiveQuery]] to populate","sourceCodeStart":1153,"sourceCodeEnd":1189,"githubUrl":"https://github.com/yiisoft/yii2/blob/66f00d18a29b520f85e8e8f1e32d1e7e7b556cac/framework/db/BaseActiveRecord.php#L1153-L1189","documentation":"getOldPrimaryKey() returns the key value(s) the record was loaded with, reading static::primaryKey() first; an empty key list means the model cannot identify its row, so a plain Exception (not InvalidConfigException) is thrown instructing you to define a table primary key or override primaryKey(). updateInternal()/deleteInternal() call it with $asArray = true, so save() and delete() on a keyless model surface here.","triggerScenarios":"$model->save() on an existing record or $model->delete() when primaryKey() returns [] — keyless table/view, override removed, or schema cache stale after the key was dropped; calling getOldPrimaryKey() directly for logging or comparison.","commonSituations":"AR over database views; legacy tables without a PRIMARY KEY; custom AR subclasses that forgot the primaryKey() override; cached schema metadata after DDL changes.","solutions":["Add a primary key to the underlying table","Override primaryKey() in the model to return the identifying column name(s)","For view-backed read-only models, never call save()/delete(); query with find() only","Flush the schema cache after primary-key changes in the database"],"exampleFix":"// before\nclass ReportRow extends \\yii\\db\\ActiveRecord\n{\n    public static function tableName() { return 'vw_report'; }\n}\nReportRow::findOne(5)->delete(); // throws: no primary key\n\n// after\nclass ReportRow extends \\yii\\db\\ActiveRecord\n{\n    public static function tableName() { return 'vw_report'; }\n    public static function primaryKey() { return ['report_id']; }\n}","handlingStrategy":"validation","validationCode":"if (empty($model::primaryKey())) {\n    throw new LogicException(get_class($model) . ' has no primary key; save()/delete() are unavailable.');\n}\n$model->delete();","typeGuard":null,"tryCatchPattern":"try {\n    $model->delete();\n} catch (yii\\db\\Exception $e) {\n    if (strpos($e->getMessage(), 'does not have a primary key') !== false) {\n        throw new RuntimeException('Model ' . get_class($model) . ' cannot be persisted: define primaryKey().', 0, $e);\n    }\n    throw $e;\n}","preventionTips":["Define a primary key (table constraint or primaryKey() override) before enabling writes on any AR class","Mark view-backed models read-only and exclude them from save/delete code paths","Flush schema cache after key changes so primaryKey() reflects reality"],"tags":["primary-key","active-record","schema","save","delete"],"backgroundTag":"missing-primary-key","analyzedSha":"66f00d18a29b520f85e8e8f1e32d1e7e7b556cac","analyzedAt":"2026-08-17T05:17:23.470Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}