{"record":{"id":"128b6c4212cc708d","repo":"redis/redis-py","slug":"bad-query-type-type-query","errorCode":null,"errorMessage":"Bad query type {type(query)}","messagePattern":"Bad query type (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"redis/commands/search/commands.py","lineNumber":1309,"sourceCode":"        args = []\n        if len(query_params) > 0:\n            args.append(\"PARAMS\")\n            args.append(len(query_params) * 2)\n            for key, value in query_params.items():\n                args.append(key)\n                args.append(value)\n        return args\n\n    def _mk_query_args(\n        self, query, query_params: Optional[Dict[str, Union[str, int, float, bytes]]]\n    ):\n        args = [self.index_name]\n\n        if isinstance(query, str):\n            # convert the query from a text to a query object\n            query = Query(query)\n        if not isinstance(query, Query):\n            raise ValueError(f\"Bad query type {type(query)}\")\n\n        args += query.get_args()\n        args += self.get_params_args(query_params)\n\n        return args, query\n\n    def search(\n        self,\n        query: Union[str, Query],\n        query_params: Union[Dict[str, Union[str, int, float, bytes]], None] = None,\n    ):\n        \"\"\"\n        Search the index for a given query, and return a result of documents\n\n        ### Parameters\n\n        - **query**: the search query. Either a text for simple queries with\n                     default parameters, or a Query object for complex queries.","sourceCodeStart":1291,"sourceCodeEnd":1327,"githubUrl":"https://github.com/redis/redis-py/blob/6a6b581b48225afa0b76912d1028c6035baee932/redis/commands/search/commands.py#L1291-L1327","documentation":"Raised by _mk_query_args() (redis/commands/search/commands.py:1309) as a ValueError when the query argument to FT.SEARCH is neither a str nor a Query object. The library accepts a raw query string (auto-wrapped in Query) or a Query instance; anything else (dict, int, None, bytes) is rejected before the command is built.","triggerScenarios":"Calling index.search(None), index.search({'q': 'foo'}), index.search(123), or passing a dict/AggregateRequest to search() instead of aggregate().","commonSituations":"Passing the wrong request type (AggregateRequest belongs to aggregate(), not search()), None from an empty input field, or a parsed JSON/dict that was not converted to a Query.","solutions":["Pass a query string or a Query object to search().","Use aggregate() with an AggregateRequest for aggregation queries.","Coerce: query = Query(str(raw)) if raw is not None else Query('*')."],"exampleFix":"# before\nindex.search(user_input)  # user_input is a dict\n# after\nfrom redis.commands.search.query import Query\nindex.search(Query(user_input.get('q', '*')))","handlingStrategy":"type-guard","validationCode":"from redis.commands.search.query import Query\n\ndef safe_search_query(q):\n    if isinstance(q, Query):\n        return q\n    if isinstance(q, str):\n        return Query(q)\n    raise TypeError('search query must be str or Query')","typeGuard":"from typing import Union\nfrom redis.commands.search.query import Query\n\ndef is_search_query(q) -> bool:\n    return isinstance(q, (str, Query))","tryCatchPattern":"try:\n    index.search(q)\nexcept ValueError as e:\n    if 'Bad query type' in str(e):\n        index.search(Query(str(q)))\n    else:\n        raise","preventionTips":["Always pass a str or Query to search(); use aggregate() for AggregateRequest.","Wrap untyped input in Query(str(...)) at the boundary.","Guard against None: substitute Query('*')."],"tags":["search","query","valueerror","redisearch","argument-validation"],"backgroundTag":null,"analyzedSha":"6a6b581b48225afa0b76912d1028c6035baee932","analyzedAt":"2026-08-10T12:52:44.840Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}