{"record":{"id":"336eb3971761e704","repo":"yiisoft/yii2","slug":"class-must-have-a-primary-key","errorCode":null,"errorMessage":"\"{class}\" must have a primary key.","messagePattern":"\"(.+?)\" must have a primary key\\.","errorType":"exception","errorClass":"yii\\base\\InvalidConfigException","httpStatus":null,"severity":"error","filePath":"framework/db/BaseActiveRecord.php","lineNumber":142,"sourceCode":"     * Finds ActiveRecord instance(s) by the given condition.\n     * This method is internally called by [[findOne()]] and [[findAll()]].\n     * @param mixed $condition please refer to [[findOne()]] for the explanation of this parameter\n     * @return ActiveQueryInterface the newly created [[ActiveQueryInterface|ActiveQuery]] instance.\n     * @throws InvalidConfigException if there is no primary key defined\n     * @internal\n     */\n    protected static function findByCondition($condition)\n    {\n        $query = static::find();\n\n        if (!ArrayHelper::isAssociative($condition) && !$condition instanceof ExpressionInterface) {\n            // query by primary key\n            $primaryKey = static::primaryKey();\n            if (isset($primaryKey[0])) {\n                // if condition is scalar, search for a single primary key, if it is array, search for multiple primary key values\n                $condition = [$primaryKey[0] => is_array($condition) ? array_values($condition) : $condition];\n            } else {\n                throw new InvalidConfigException('\"' . get_called_class() . '\" must have a primary key.');\n            }\n        }\n\n        return $query->andWhere($condition);\n    }\n\n    /**\n     * Updates the whole table using the provided attribute values and conditions.\n     *\n     * For example, to change the status to be 1 for all customers whose status is 2:\n     *\n     * ```\n     * Customer::updateAll(['status' => 1], 'status = 2');\n     * ```\n     *\n     * @param array $attributes attribute values (name-value pairs) to be saved into the table\n     * @param string|array $condition the conditions that will be put in the WHERE part of the UPDATE SQL.\n     * Please refer to [[Query::where()]] on how to specify this parameter.","sourceCodeStart":124,"sourceCodeEnd":160,"githubUrl":"https://github.com/yiisoft/yii2/blob/66f00d18a29b520f85e8e8f1e32d1e7e7b556cac/framework/db/BaseActiveRecord.php#L124-L160","documentation":"BaseActiveRecord::findByCondition() implements findOne()/findAll() for all ActiveRecord flavors built on the base class. When the condition is a scalar or a non-associative array (and not an ExpressionInterface), it is interpreted as primary key value(s) and wrapped as [pk => value]; with static::primaryKey() empty, the wrap is impossible and InvalidConfigException is thrown.","triggerScenarios":"Model::findOne(5) or Model::findAll([1, 2]) on any AR subclass whose backing table/schema declares no primary key and whose primaryKey() is not overridden — including custom AR classes extending BaseActiveRecord directly.","commonSituations":"Keyless tables or views modeled as AR; custom AR implementations (file/API-backed) that never defined primaryKey(); schema metadata unavailable for the storage; code ported from another AR that assumed a key.","solutions":["Define a primary key in the underlying storage and let primaryKey() pick it up","Override primaryKey() to return the identifying column name(s)","Call with an associative condition instead: Model::findOne(['uuid' => $uuid])","Bypass findOne/findAll: Model::find()->andWhere(['uuid' => $uuid])->one()"],"exampleFix":"// before\n$session = SessionModel::findOne($id); // throws: no PK defined\n\n// after\n$session = SessionModel::find()->where(['session_id' => $id])->one();","handlingStrategy":"validation","validationCode":"if (!ArrayHelper::isAssociative($condition) && empty($modelClass::primaryKey())) {\n    // scalar condition on a PK-less model: switch to explicit column lookup\n    $condition = [$fallbackColumn => $condition];\n}\n$model = $modelClass::findOne($condition);","typeGuard":null,"tryCatchPattern":"try {\n    $model = SessionModel::findOne($id);\n} catch (yii\\base\\InvalidConfigException $e) {\n    if (strpos($e->getMessage(), 'must have a primary key') !== false) {\n        $model = SessionModel::find()->where(['session_id' => $id])->one();\n    } else {\n        throw $e;\n    }\n}","preventionTips":["Define primaryKey() in every custom BaseActiveRecord subclass as a skeleton requirement","Use associative conditions in generic code paths shared across AR flavors","Assert non-empty primaryKey() in model unit tests"],"tags":["primary-key","find","active-record","baseactiverecord"],"backgroundTag":"missing-primary-key","analyzedSha":"66f00d18a29b520f85e8e8f1e32d1e7e7b556cac","analyzedAt":"2026-08-17T05:17:23.470Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}