{"id":"6eeee129f31b8cae","repo":"psycopg/psycopg2","slug":"no-format-conversion-supported-by-sql","errorCode":null,"errorMessage":"no format conversion supported by SQL","messagePattern":"no format conversion supported by SQL","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"lib/sql.py","lineNumber":232,"sourceCode":"\n            >>> print(sql.SQL(\"select * from {} where {} = %s\")\n            ...     .format(sql.Identifier('people'), sql.Identifier('id'))\n            ...     .as_string(conn))\n            select * from \"people\" where \"id\" = %s\n\n            >>> print(sql.SQL(\"select * from {tbl} where {pkey} = %s\")\n            ...     .format(tbl=sql.Identifier('people'), pkey=sql.Identifier('id'))\n            ...     .as_string(conn))\n            select * from \"people\" where \"id\" = %s\n\n        \"\"\"\n        rv = []\n        autonum = 0\n        for pre, name, spec, conv in _formatter.parse(self._wrapped):\n            if spec:\n                raise ValueError(\"no format specification supported by SQL\")\n            if conv:\n                raise ValueError(\"no format conversion supported by SQL\")\n            if pre:\n                rv.append(SQL(pre))\n\n            if name is None:\n                continue\n\n            if name.isdigit():\n                if autonum:\n                    raise ValueError(\n                        \"cannot switch from automatic field numbering to manual\")\n                rv.append(args[int(name)])\n                autonum = None\n\n            elif not name:\n                if autonum is None:\n                    raise ValueError(\n                        \"cannot switch from manual field numbering to automatic\")\n                rv.append(args[autonum])","sourceCodeStart":214,"sourceCodeEnd":250,"githubUrl":"https://github.com/psycopg/psycopg2/blob/3a6d9d6ddc6b53eaa80b712f5fa6b23abbdc38db/lib/sql.py#L214-L250","documentation":"Raised by SQL.format() (lib/sql.py:232) when a placeholder carries a conversion flag (!r, !s, !a), e.g. {0!r}. Conversions imply a Python-level repr/str/ascii transformation, which is meaningless for Composable objects (Identifier/Literal/SQL render themselves), so the library rejects them up front. Like error [20], it is detected during the single string.Formatter().parse() pass over the template.","triggerScenarios":"Calling sql.SQL(...).format(...) with a template containing {0!r}, {x!s}, or any {name!conv} / {idx!conv} placeholder. Example: sql.SQL(\"select {0!r}\").format(sql.Identifier('x')).","commonSituations":"Pasting debug/log strings that used {var!r} for repr-style output into an SQL template. Assuming SQL.format mirrors str.format's full grammar.","solutions":["Drop the '!conv' suffix from placeholders (e.g. {0!r} -> {0}, {x!s} -> {x}).","If you want a quoted SQL literal of a Python value, use sql.Literal(value) and splice it via the placeholder.","Render to a string first and format in plain Python if you truly need repr."],"exampleFix":"// before\nq = sql.SQL(\"values {0!r}\").format(val)\n// after\nq = sql.SQL(\"values {}\").format(sql.Literal(val))","handlingStrategy":"validation","validationCode":"import string\n\ndef sql_template_is_clean(template: str) -> bool:\n    for _pre, _name, spec, conv in string.Formatter().parse(template):\n        if spec or conv:\n            return False\n    return True\n\nassert sql_template_is_clean(tpl)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never paste {var!r}/{var!s} debug-style placeholders into SQL templates.","If you need a quoted literal value, use sql.Literal(value) and splice it.","Lint SQL template strings for '!' inside placeholders."],"tags":["psycopg2","sql-composition","format","valueerror"],"analyzedSha":"3a6d9d6ddc6b53eaa80b712f5fa6b23abbdc38db","analyzedAt":"2026-08-04T19:56:51.958Z","schemaVersion":2}