{"record":{"id":"60d99e61ee5afccb","repo":"mongodb/laravel-mongodb","slug":"cannot-have-both-id-and-id-fields","errorCode":null,"errorMessage":"Cannot have both \"id\" and \"_id\" fields.","messagePattern":"Cannot have both \"id\" and \"_id\" fields\\.","errorType":"exception","errorClass":"InvalidArgumentException","httpStatus":null,"severity":"error","filePath":"src/Query/Grammar.php","lineNumber":50,"sourceCode":"{\n    /**\n     * Prepare fields for the MongoDB query by aliasing \"id\" to \"_id\" and handling arrow notation.\n     * Users can override this method to customize field aliasing behavior.\n     *\n     * @param array<string, mixed> $values The values to prepare\n     * @param bool                 $root   Whether this is the root level (affects embedded id field handling)\n     * @psalm-param T $values\n     *\n     * @return array<string, mixed> The prepared values\n     * @psalm-return T\n     *\n     * @template T of array\n     */\n    public function prepareFieldsForQuery(array $values, bool $root = true): array\n    {\n        if (array_key_exists('id', $values) && ($root || $this->connection->getRenameEmbeddedIdField())) {\n            if (array_key_exists('_id', $values) && $values['id'] !== $values['_id']) {\n                throw new InvalidArgumentException('Cannot have both \"id\" and \"_id\" fields.');\n            }\n\n            $values['_id'] = $values['id'];\n            unset($values['id']);\n        }\n\n        foreach ($values as $key => $value) {\n            if (! is_string($key)) {\n                continue;\n            }\n\n            // \"->\" arrow notation for subfields is an alias for \".\" dot notation\n            if (str_contains($key, '->')) {\n                $newKey = str_replace('->', '.', $key);\n                if (array_key_exists($newKey, $values) && $value !== $values[$newKey]) {\n                    throw new InvalidArgumentException(sprintf('Cannot have both \"%s\" and \"%s\" fields.', $key, $newKey));\n                }\n","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/mongodb/laravel-mongodb/blob/0634653039468ceb0268a69192bdac64469ed043/src/Query/Grammar.php#L32-L68","documentation":"When preparing an attribute array for a MongoDB query, the library renames the Eloquent-style \"id\" field to MongoDB's \"_id\". If both \"id\" and \"_id\" are present in the same array with different values, the rename would silently lose one value, so an InvalidArgumentException is thrown.","triggerScenarios":"Calling any query/write method (e.g. insert, create, update, where-style payload paths) via prepareFieldsForQuery with an array containing keys 'id' and '_id' whose values differ, at the document root (or in an embedded document when renameEmbeddedIdField is enabled).","commonSituations":"Merging Eloquent model attributes (which use 'id') with raw MongoDB documents (which use '_id'); building payloads by array_merge where a raw BSON doc and a hydrated model both contribute; deserializing JSON that includes both id keys.","solutions":["Remove one of the two keys from the payload array before passing it to the query","Normalize your data to a single convention (Eloquent 'id' or MongoDB '_id') before building the payload","If both keys must exist and be equal, keep only '_id' (the library would map 'id' to it anyway)","Audit array_merge/array_replace call sites that combine model attributes with raw documents"],"exampleFix":"// before\n$data = ['id' => '64b0...', '_id' => 'different'];\n$collection->insertOne($data);\n// after\nunset($data['id']); // keep only '_id'\n$collection->insertOne($data);","handlingStrategy":"validation","validationCode":"if (array_key_exists('id', $data) && array_key_exists('_id', $data) && $data['id'] !== $data['_id']) {\n    throw new InvalidArgumentException('Payload must not define both \"id\" and \"_id\".');\n}","typeGuard":"function hasIdConflict(array $values): bool {\n    return array_key_exists('id', $values) && array_key_exists('_id', $values) && $values['id'] !== $values['_id'];\n}","tryCatchPattern":"try {\n    $model->create($data);\n} catch (\\InvalidArgumentException $e) {\n    if (str_contains($e->getMessage(), '\"id\" and \"_id\"')) {\n        unset($data['id']);\n        $model->create($data);\n    } else { throw $e; }\n}","preventionTips":["Never mix Eloquent 'id' attributes with raw '_id' documents in one payload","Normalize payloads through model hydration before querying","Unset 'id' after mapping it to '_id' when converting formats","Add a unit test asserting payload keys for insert/update helpers"],"tags":["php","mongodb","query-builder","validation"],"backgroundTag":"conflicting-config-options","analyzedSha":"0634653039468ceb0268a69192bdac64469ed043","analyzedAt":"2026-09-15T02:56:37.067Z","contentChangedAt":"2026-09-15T02:56:37.067Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}