{"record":{"id":"4efae2da433ad8bf","repo":"mongodb/laravel-mongodb","slug":"query-not-compatible-with-cursor","errorCode":null,"errorMessage":"Query not compatible with cursor","messagePattern":"Query not compatible with cursor","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"src/Query/Builder.php","lineNumber":259,"sourceCode":"    }\n\n    /** @inheritdoc */\n    #[Override]\n    public function get($columns = [])\n    {\n        return $this->getFresh($columns);\n    }\n\n    /** @inheritdoc */\n    #[Override]\n    public function cursor($columns = [])\n    {\n        $result = $this->getFresh($columns, true);\n        if ($result instanceof LazyCollection) {\n            return $result;\n        }\n\n        throw new RuntimeException('Query not compatible with cursor');\n    }\n\n    /**\n     * Die and dump the current MongoDB query\n     *\n     * @return never-return\n     */\n    #[Override]\n    public function dd()\n    {\n        dd($this->toMql());\n    }\n\n    /**\n     * Dump the current MongoDB query\n     *\n     * @param mixed ...$args\n     *","sourceCodeStart":241,"sourceCodeEnd":277,"githubUrl":"https://github.com/mongodb/laravel-mongodb/blob/0634653039468ceb0268a69192bdac64469ed043/src/Query/Builder.php#L241-L277","documentation":"Builder::cursor() expects getFresh(..., true) to return a LazyCollection for a true streaming cursor. If the underlying query path (e.g. an aggregation result) returns something else — an array/Collection — the query is not cursor-compatible and this RuntimeException is thrown.","triggerScenarios":"Calling ->cursor() on a query whose result is not a LazyCollection, such as after ->groupBy() (which forces an aggregation pipeline executed via aggregate() returning a plain result) or other transformed queries.","commonSituations":"Developers chaining cursor() onto aggregate/groupBy queries to reduce memory, unaware that grouped results cannot stream; Laravel Eloquent Builder uses the same pattern with getQuery()->cursor().","solutions":["Remove ->groupBy() or aggregation transformations before calling cursor(), or iterate with ->get() instead.","Use cursor() only on plain find-style queries.","If memory is a concern with aggregations, use aggregateRaw with a cursor via the collection directly, or paginate."],"exampleFix":"// before\nUser::groupBy('type')->cursor();\n// after\nUser::cursor();  // or User::groupBy('type')->get()","handlingStrategy":"type-guard","validationCode":"if ($query->getQuery()->groups) {\n    // cannot cursor(); use get() or remove groupBy\n}\n$result = $query->cursor();","typeGuard":"function canUseCursor(Illuminate\\Database\\Eloquent\\Builder $q): bool { return empty($q->getQuery()->groups); }","tryCatchPattern":"try {\n    foreach ($query->cursor() as $doc) { /* ... */ }\n} catch (RuntimeException $e) {\n    if ($e->getMessage() === 'Query not compatible with cursor') {\n        foreach ($query->get() as $doc) { /* fallback */ }\n    } else { throw $e; }\n}","preventionTips":["Never chain cursor() after groupBy()/aggregate()","Use cursor() only on straightforward find-style queries","Wrap streaming iteration in try/catch with a get() fallback when unsure","Test memory-sensitive code paths with representative data"],"tags":["cursor","lazy-collection","aggregation"],"backgroundTag":"unsupported-operation","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"}