{"id":"9774cc25407246c9","repo":"psycopg/psycopg2","slug":"expected-string-or-none-as-name-got-name-r","errorCode":null,"errorMessage":"expected string or None as name, got {name!r}","messagePattern":"expected string or None as name, got (.+?)","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"lib/sql.py","lineNumber":431,"sourceCode":"        ...     sql.SQL(', ').join(sql.Placeholder() * len(names)))\n        >>> print(q1.as_string(conn))\n        insert into table (\"foo\", \"bar\", \"baz\") values (%s, %s, %s)\n\n        >>> q2 = sql.SQL(\"insert into table ({}) values ({})\").format(\n        ...     sql.SQL(', ').join(map(sql.Identifier, names)),\n        ...     sql.SQL(', ').join(map(sql.Placeholder, names)))\n        >>> print(q2.as_string(conn))\n        insert into table (\"foo\", \"bar\", \"baz\") values (%(foo)s, %(bar)s, %(baz)s)\n\n    \"\"\"\n\n    def __init__(self, name=None):\n        if isinstance(name, str):\n            if ')' in name:\n                raise ValueError(f\"invalid name: {name!r}\")\n\n        elif name is not None:\n            raise TypeError(f\"expected string or None as name, got {name!r}\")\n\n        super().__init__(name)\n\n    @property\n    def name(self):\n        \"\"\"The name of the `!Placeholder`.\"\"\"\n        return self._wrapped\n\n    def __repr__(self):\n        if self._wrapped is None:\n            return f\"{self.__class__.__name__}()\"\n        else:\n            return f\"{self.__class__.__name__}({self._wrapped!r})\"\n\n    def as_string(self, context):\n        if self._wrapped is not None:\n            return f\"%({self._wrapped})s\"\n        else:","sourceCodeStart":413,"sourceCodeEnd":449,"githubUrl":"https://github.com/psycopg/psycopg2/blob/3a6d9d6ddc6b53eaa80b712f5fa6b23abbdc38db/lib/sql.py#L413-L449","documentation":"Raised by Placeholder.__init__() (lib/sql.py:431) when the name argument is neither a str nor None. A str becomes a named placeholder (%(name)s); None (or omitted) becomes a positional %s. Any other type (int, bytes, list, etc.) has no defined rendering and is rejected with TypeError. Note in particular that an int like 0 does NOT mean 'positional index 0' - positional placeholders take None.","triggerScenarios":"sql.Placeholder(0) (mistakenly treating it as a positional index), sql.Placeholder(b'x'), sql.Placeholder(['x']), sql.Placeholder(123).","commonSituations":"Confusing Placeholder(0) with positional-by-index (it is not); passing bytes names; passing a list/tuple accidentally; copy-paste from code that numbered placeholders.","solutions":["For a positional placeholder, pass None or omit the argument: sql.Placeholder() or sql.Placeholder(None).","For a named placeholder, pass a str.","Add a type check upstream so only str/None reach Placeholder."],"exampleFix":"// before\nph = sql.Placeholder(0)\n// after\nph = sql.Placeholder()        # positional %s\n# or\nph = sql.Placeholder('name')  # named %(name)s","handlingStrategy":"type-guard","validationCode":"def make_placeholder(name=None):\n    if name is not None and not isinstance(name, str):\n        raise TypeError(f'Placeholder name must be str or None, got {type(name).__name__}')\n    return sql.Placeholder(name)","typeGuard":"def is_valid_placeholder_arg(name) -> bool:\n    return name is None or isinstance(name, str)","tryCatchPattern":null,"preventionTips":["Remember Placeholder(0) is NOT positional-by-index - use Placeholder() for %s.","Omit the argument entirely for positional placeholders to avoid confusion.","Type-check dynamic names before passing them in."],"tags":["psycopg2","sql-composition","placeholder","typeerror"],"analyzedSha":"3a6d9d6ddc6b53eaa80b712f5fa6b23abbdc38db","analyzedAt":"2026-08-04T19:56:51.958Z","schemaVersion":2}