{"id":"f2123c07f13067f3","repo":"pypa/pip","slug":"should-pass-a-unicode-string-to-the-function-rathe","errorCode":null,"errorMessage":"should pass a unicode string to the function rather than a byte string.","messagePattern":"should pass a unicode string to the function rather than a byte string\\.","errorType":"validation","errorClass":"IDNAError","httpStatus":null,"severity":"error","filePath":"src/pip/_vendor/idna/core.py","lineNumber":549,"sourceCode":"    :param transitional: Forwarded to :func:`uts46_remap` when ``uts46``\n        is ``True``. Deprecated: emits a :class:`DeprecationWarning` and\n        will be removed in a future version.\n    :returns: The encoded domain as ASCII :class:`bytes`.\n    :raises IDNAError: If the domain is empty, contains an invalid label,\n        or exceeds the maximum domain length.\n    \"\"\"\n    if transitional:\n        warnings.warn(\n            \"Transitional processing has been removed from UTS #46. \"\n            \"The transitional argument will be removed in a future version.\",\n            DeprecationWarning,\n            stacklevel=2,\n        )\n    if not isinstance(s, str):\n        try:\n            s = str(s, \"ascii\")\n        except (UnicodeDecodeError, TypeError) as err:\n            raise IDNAError(\"should pass a unicode string to the function rather than a byte string.\") from err\n    if len(s) > _max_input_length:\n        raise IDNAError(\"Domain too long\")\n    if uts46:\n        s = uts46_remap(s, std3_rules, transitional)\n\n    # Reject inputs that exceed the maximum DNS domain length up-front\n    # to avoid expensive computation on long inputs.\n    if not valid_string_length(s, trailing_dot=True):\n        raise IDNAError(\"Domain too long\")\n\n    trailing_dot = False\n    result = []\n    labels = s.split(\".\") if strict else _unicode_dots_re.split(s)\n    if not labels or labels == [\"\"]:\n        raise IDNAError(\"Empty domain\")\n    if labels[-1] == \"\":\n        del labels[-1]\n        trailing_dot = True","sourceCodeStart":531,"sourceCodeEnd":567,"githubUrl":"https://github.com/pypa/pip/blob/d7d0d0a39494e28ec1c407bd0680e4a4d1067791/src/pip/_vendor/idna/core.py#L531-L567","documentation":"Raised by encode() (core.py:549) when the input is not a str and cannot be decoded as ASCII — i.e. the caller passed a bytes/bytearray containing non-ASCII bytes. idna.encode() expects a Unicode (str) domain; bytes input is only tolerated if it is pure ASCII, otherwise it raises IDNAError with this message. The original UnicodeDecodeError/TypeError is chained as the cause.","triggerScenarios":"Calling idna.encode() with bytes that contain non-ASCII octets, e.g. idna.encode(b'münchen.com'), idna.encode(some_bytes_variable), or passing a UTF-8-encoded byte string read from a file/socket without decoding first.","commonSituations":"Reading domains from binary sources (files opened 'rb', network sockets, database BLOB columns) and forgetting to .decode('utf-8'); mixing str/bytes across an API boundary; porting code that previously handled bytes; or framework code that passes request bodies as bytes into a URL/IDNA path.","solutions":["Decode the bytes to str with the correct encoding (usually UTF-8) before calling encode: idna.encode(s.decode('utf-8')).","Make the caller-side type explicit: accept only str at your function boundary and coerce/validate early.","If the value really is an ASCII A-label in bytes, decode as ASCII first: s.decode('ascii')."],"exampleFix":"// before\nidna.encode(b'münchen.com')  # bytes with non-ASCII -> IDNAError\n\n// after\nidna.encode('münchen.com')              # pass a str\n# or, coming from bytes:\nidna.encode(raw.decode('utf-8'))","handlingStrategy":"type-guard","validationCode":"def to_unicode_domain(s):\n    if isinstance(s, (bytes, bytearray)):\n        return s.decode('utf-8')\n    if not isinstance(s, str):\n        raise TypeError(f'expected str or bytes, got {type(s).__name__}')\n    return s\n\nencoded = idna.encode(to_unicode_domain(raw))","typeGuard":"def is_unicode_str(s) -> bool:\n    return isinstance(s, str)","tryCatchPattern":"import idna\n\ntry:\n    encoded = idna.encode(raw)\nexcept idna.IDNAError as err:\n    if 'unicode string' in str(err):\n        # raw was bytes with non-ASCII; decode and retry\n        encoded = idna.encode(raw.decode('utf-8'))\n    else:\n        raise","preventionTips":["Always decode bytes to str (UTF-8) at the boundary before passing to idna.","Type-annotate domain parameters as str and enforce with a runtime check.","Open files holding domains in text mode ('r', encoding='utf-8'), not binary."],"tags":["idna","domain","types","bytes","encoding"],"analyzedSha":"d7d0d0a39494e28ec1c407bd0680e4a4d1067791","analyzedAt":"2026-08-04T20:55:04.259Z","schemaVersion":2}