{"id":"afb746a510072034","repo":"redis/redis-py","slug":"must-provide-aggregaterequest-object-or-query-obje","errorCode":null,"errorMessage":"Must provide AggregateRequest object or Query object.","messagePattern":"Must provide AggregateRequest object or Query object\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"redis/commands/search/commands.py","lineNumber":1514,"sourceCode":"        **query_params**: Define one or more value parameters.\n        Each parameter has a name and a value.\n\n        \"\"\"\n        st = time.monotonic()\n        cmd = [PROFILE_CMD, self.index_name, \"\"]\n        if limited:\n            cmd.append(\"LIMITED\")\n        cmd.append(\"QUERY\")\n\n        if isinstance(query, AggregateRequest):\n            cmd[2] = \"AGGREGATE\"\n            cmd += query.build_args()\n        elif isinstance(query, Query):\n            cmd[2] = \"SEARCH\"\n            cmd += query.get_args()\n            cmd += self.get_params_args(query_params)\n        else:\n            raise ValueError(\"Must provide AggregateRequest object or Query object.\")\n\n        res = self.execute_command(*cmd)\n\n        return self._parse_results(\n            PROFILE_CMD, res, query=query, duration=(time.monotonic() - st) * 1000.0\n        )\n\n    def spellcheck(self, query, distance=None, include=None, exclude=None):\n        \"\"\"\n        Issue a spellcheck query\n\n        Args:\n\n            query: search query.\n            distance: the maximal Levenshtein distance for spelling\n                       suggestions (default: 1, max: 4).\n            include: specifies an inclusion custom dictionary.\n            exclude: specifies an exclusion custom dictionary.","sourceCodeStart":1496,"sourceCodeEnd":1532,"githubUrl":"https://github.com/redis/redis-py/blob/da03cdc7e8731092b13e395605c3c1fb2de25de1/redis/commands/search/commands.py#L1496-L1532","documentation":"Raised by profile() when the query argument is neither an AggregateRequest nor a Query. profile() dispatches to FT.PROFILE with either 'AGGREGATE' or 'SEARCH' mode, so it must know which; a Cursor, string, or any other type is rejected.","triggerScenarios":"Call client.profile(query) where query is a string, a Cursor, an int, None, or any type other than AggregateRequest / Query.","commonSituations":"Passing a raw query string (profile requires the strongly-typed object so it can pick the mode); passing a Cursor (cursors are not profiled); mixing up profile() with search()/aggregate().","solutions":["Pass a Query object for SEARCH profiling or an AggregateRequest for AGGREGATE profiling.","Build the right wrapper: profile(Query('@x:1')) or profile(AggregateRequest('*')).","If you only want the plan without timing, use explain() for searches."],"exampleFix":"// before\nclient.profile('@title:hello')\n// after\nfrom redis.commands.search import Query\nclient.profile(Query('@title:hello'))","handlingStrategy":"type-guard","validationCode":"from redis.commands.search import Query\nfrom redis.commands.search.aggregation import AggregateRequest\n\ndef safe_profile(client, query, limited=False, query_params=None):\n    if isinstance(query, str):\n        raise TypeError(\"profile() needs a Query or AggregateRequest, not a string\")\n    if not isinstance(query, (Query, AggregateRequest)):\n        raise TypeError(f\"query must be Query/AggregateRequest, got {type(query)}\")\n    return client.profile(query, limited=limited, query_params=query_params)","typeGuard":"from redis.commands.search import Query\nfrom redis.commands.search.aggregation import AggregateRequest\n\ndef is_profile_query(v) -> bool:\n    return isinstance(v, (Query, AggregateRequest))","tryCatchPattern":"try:\n    client.profile(query)\nexcept ValueError as e:\n    if \"AggregateRequest object or Query object\" in str(e):\n        from redis.commands.search import Query\n        client.profile(Query(str(query)))\n    else:\n        raise","preventionTips":["profile() picks SEARCH vs AGGREGATE from the wrapper type — pass the right one.","Don't pass cursors to profile() — profile a fresh query instead.","Use explain() if you only need the plan without timing."],"tags":["redis-search","validation","profile","valueerror"],"analyzedSha":"da03cdc7e8731092b13e395605c3c1fb2de25de1","analyzedAt":"2026-08-04T20:26:47.563Z","schemaVersion":2}