{"id":"61a954036fc6cca0","repo":"sqlalchemy/sqlalchemy","slug":"query-dictionary-values-must-be-strings-or-sequenc","errorCode":null,"errorMessage":"Query dictionary values must be strings or sequences of strings","messagePattern":"Query dictionary values must be strings or sequences of strings","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"lib/sqlalchemy/engine/url.py","lineNumber":273,"sourceCode":"        @overload\n        def _assert_value(\n            val: str,\n        ) -> str: ...\n\n        @overload\n        def _assert_value(\n            val: Sequence[str],\n        ) -> Union[str, Tuple[str, ...]]: ...\n\n        def _assert_value(\n            val: Union[str, Sequence[str]],\n        ) -> Union[str, Tuple[str, ...]]:\n            if isinstance(val, str):\n                return val\n            elif isinstance(val, collections_abc.Sequence):\n                return tuple(_assert_value(elem) for elem in val)\n            else:\n                raise TypeError(\n                    \"Query dictionary values must be strings or \"\n                    \"sequences of strings\"\n                )\n\n        def _assert_str(v: str) -> str:\n            if not isinstance(v, str):\n                raise TypeError(\"Query dictionary keys must be strings\")\n            return v\n\n        dict_items: Iterable[Tuple[str, Union[Sequence[str], str]]]\n        if isinstance(dict_, collections_abc.Sequence):\n            dict_items = dict_\n        else:\n            dict_items = dict_.items()\n\n        return util.immutabledict(\n            {\n                _assert_str(key): _assert_value(","sourceCodeStart":255,"sourceCodeEnd":291,"githubUrl":"https://github.com/sqlalchemy/sqlalchemy/blob/d9b44cb731bd27e6e82c99a3c0fb598214e8e7ff/lib/sqlalchemy/engine/url.py#L255-L291","documentation":"URL._str_dict (engine/url.py:273) validates each value of the query dict passed to URL.create(query=...) / update_query; values must be a str or a Sequence of str (e.g. list/tuple of strings). Any other type (int, dict, None, bool, set) raises TypeError('Query dictionary values must be strings or sequences of strings'). Keys are validated separately ('Query dictionary keys must be strings').","triggerScenarios":"Passing `URL.create('postgresql', query={'connect_timeout': 10})` (int value), `query={'options': {'k': 'v'}}` (dict value), `query={'sslmode': True}` (bool), or a set as a multi-value. Common when building URLs from typed config objects where numerics/bools aren't stringified.","commonSituations":"Env/config ingestion without type normalization; passing booleans as Python bools for sslmode/ssl flags; multi-tenant query builders concatenating dicts; pydantic settings models exposing int fields directly into query.","solutions":["Stringify every query value before URL.create: `query={'connect_timeout': str(cfg.timeout)}`.","For booleans use the DB-accepted string form (e.g. `'true'`/`'false'` or `'require'`).","For multi-value parameters pass a list of strings, e.g. `query={'host': ['h1', 'h2']}`.","Add a normalization step over the config dict: `{k: str(v) if not isinstance(v, (list, tuple)) else [str(x) for x in v] for k, v in cfg.items()}`."],"exampleFix":"// before\nurl = URL.create(\n    'postgresql', username='u', password='p', host='db',\n    query={'connect_timeout': 10, 'sslmode': True},   # TypeError\n)\n\n// after\nurl = URL.create(\n    'postgresql', username='u', password='p', host='db',\n    query={\n        'connect_timeout': str(10),\n        'sslmode': 'require',\n    },\n)","handlingStrategy":"validation","validationCode":"import collections.abc as cabc\n\ndef validate_query_dict(query):\n    \"\"\"Ensure every query value is a str or a sequence of str (no bytes, no ints).\"\"\"\n    cleaned = {}\n    for k, v in dict(query).items():\n        if not isinstance(k, str):\n            raise TypeError('Query key %r must be str' % (k,))\n        if isinstance(v, str) or not isinstance(v, cabc.Sequence):\n            if not isinstance(v, str):\n                raise TypeError('Query value for %r must be str or seq of str' % (k,))\n            cleaned[k] = v\n        else:\n            seq = list(v)\n            if any(not isinstance(e, str) for e in seq):\n                raise TypeError('All elements in query[%r] must be str' % (k,))\n            cleaned[k] = tuple(seq)\n    return cleaned\n\n# usage: URL.create(..., query=validate_query_dict(raw_query))","typeGuard":"import collections.abc as cabc\n\ndef is_valid_query_value(v) -> bool:\n    if isinstance(v, str):\n        return True\n    if isinstance(v, cabc.Sequence):\n        return all(isinstance(e, str) for e in v)\n    return False","tryCatchPattern":null,"preventionTips":["URL query values must be str or tuple/list of str - never ints, floats, bytes, or None.","Coerce booleans/numbers to 'true'/'1'/etc. explicitly before putting them in the query dict.","For non-string DBAPI connect args, pass them via create_engine(connect_args={...}) instead of the URL query."],"tags":["sqlalchemy","url","query-dict","configuration","typeerror"],"analyzedSha":"d9b44cb731bd27e6e82c99a3c0fb598214e8e7ff","analyzedAt":"2026-08-01T17:20:52.075Z","schemaVersion":2}