{"record":{"id":"1593ea917985c4f3","repo":"mongodb/laravel-mongodb","slug":"the-value-used-as-a-document-id-or-relation-key-cannot","errorCode":null,"errorMessage":"The value used as a document id or relation key cannot contain the MongoDB operator \"%s\".","messagePattern":"The value used as a document id or relation key cannot contain the MongoDB operator \"(.+?)\"\\.","errorType":"exception","errorClass":"InvalidArgumentException","httpStatus":null,"severity":"error","filePath":"src/Query/Builder.php","lineNumber":1260,"sourceCode":"        return $id;\n    }\n\n    /**\n     * A plain array without \"$\"-prefixed keys is allowed, so composite _id values keep working.\n     *\n     * @internal\n     *\n     * @throws InvalidArgumentException when the value contains a MongoDB operator.\n     */\n    public static function assertKeyIsNotOperator(mixed $value): void\n    {\n        if (! is_array($value)) {\n            return;\n        }\n\n        foreach ($value as $key => $item) {\n            if (is_string($key) && str_starts_with($key, '$')) {\n                throw new InvalidArgumentException(sprintf(\n                    'The value used as a document id or relation key cannot contain the MongoDB operator \"%s\".',\n                    $key,\n                ));\n            }\n\n            self::assertKeyIsNotOperator($item);\n        }\n    }\n\n    /**\n     * Add a basic where clause to the query.\n     *\n     * If 1 argument, the signature is: where(array|Closure $where)\n     * If 2 arguments, the signature is: where(string $column, mixed $value)\n     * If 3 arguments, the signature is: where(string $colum, string $operator, mixed $value)\n     *\n     * With 1 or 2 arguments, an array value is read as a MongoDB operator document,\n     * so never pass unvalidated input there, it is open to MQL injection.","sourceCodeStart":1242,"sourceCodeEnd":1278,"githubUrl":"https://github.com/mongodb/laravel-mongodb/blob/0634653039468ceb0268a69192bdac64469ed043/src/Query/Builder.php#L1242-L1278","documentation":"The library scans document ids / relation keys and rejects values that look like MongoDB query operators — array keys starting with '$' such as '$gt' or '$ne'. This prevents untrusted input from injecting operator documents where a plain scalar id is expected, e.g. when finding by _id or resolving relations.","triggerScenarios":"User-controlled input like ['id' => ['$gt' => '']] reaching ->find($id), ->findOrFail($id), relation resolution (belongsTo/hasMany keys), or ->convertKey(); any array value passed as a key with a '$'-prefixed string key at any nesting depth.","commonSituations":"Passing raw request input directly to find()/where on _id; noSQL-injection attempts via JSON payloads; storing operator-shaped arrays in document id columns.","solutions":["Cast ids to string/int before use: ->find((string) $request->input('id')).","Validate input is scalar before treating it as a key: if (!is_scalar($id)) abort(400).","Use the library's ObjectId conversion helpers instead of raw arrays for ids.","Sanitize nested user input so no array keys beginning with '$' survive (recursive whitelist)."],"exampleFix":"// before\n$user = User::find($request->input('id')); // id = {\"$gt\": \"\"}\n// after\n$id = (string) $request->input('id');\n$user = User::find($id);","handlingStrategy":"type-guard","validationCode":"function assertScalarId(mixed $id): string|int {\n    if (!is_string($id) && !is_int($id)) {\n        throw new InvalidArgumentException('Document id must be scalar');\n    }\n    return $id;\n}","typeGuard":"function isSafeId(mixed $v): bool {\n    return is_string($v) || is_int($v);\n}","tryCatchPattern":null,"preventionTips":["Cast ids to string/int at the request boundary.","Reject nested arrays in ids and relation keys.","Never pass raw JSON payloads as ids."],"tags":["php","laravel-mongodb","security","nosql-injection"],"backgroundTag":"invalid-argument-value","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"}