{"record":{"id":"9870fbc680d42878","repo":"microsoft/markitdown","slug":"invalid-source-type-type-source-expected-str","errorCode":null,"errorMessage":"Invalid source type: {type(source)}. Expected str, requests.Response, BinaryIO.","messagePattern":"Invalid source type: (.+?)\\. Expected str, requests\\.Response, BinaryIO\\.","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/markitdown/src/markitdown/_markitdown.py","lineNumber":321,"sourceCode":"\n                return self.convert_uri(source, stream_info=stream_info, **_kwargs)\n            else:\n                return self.convert_local(source, stream_info=stream_info, **kwargs)\n        # Path object\n        elif isinstance(source, Path):\n            return self.convert_local(source, stream_info=stream_info, **kwargs)\n        # Request response\n        elif isinstance(source, requests.Response):\n            return self.convert_response(source, stream_info=stream_info, **kwargs)\n        # Binary stream\n        elif (\n            hasattr(source, \"read\")\n            and callable(source.read)\n            and not isinstance(source, io.TextIOBase)\n        ):\n            return self.convert_stream(source, stream_info=stream_info, **kwargs)\n        else:\n            raise TypeError(\n                f\"Invalid source type: {type(source)}. Expected str, requests.Response, BinaryIO.\"\n            )\n\n    def convert_local(\n        self,\n        path: Union[str, Path],\n        *,\n        stream_info: Optional[StreamInfo] = None,\n        file_extension: Optional[str] = None,  # Deprecated -- use stream_info\n        url: Optional[str] = None,  # Deprecated -- use stream_info\n        **kwargs: Any,\n    ) -> DocumentConverterResult:\n        if isinstance(path, Path):\n            path = str(path)\n\n        # Build a base StreamInfo object from which to start guesses\n        base_guess = StreamInfo(\n            local_path=path,","sourceCodeStart":303,"sourceCodeEnd":339,"githubUrl":"https://github.com/microsoft/markitdown/blob/fd239d5d2be43d9b68329730206b9312c7d5a388/packages/markitdown/src/markitdown/_markitdown.py#L303-L339","documentation":"MarkItDown.convert() dispatches on the type of 'source': str/Path goes to convert_local, requests.Response to convert_response, and objects with a callable read() that are not io.TextIOBase to convert_stream. Anything else (bytes, int, an httpx.Response, a text-mode file, a tempfs handle without read) hits the final TypeError. The message names the received type so you can immediately see which branch you missed.","triggerScenarios":"Calling md.convert() with raw bytes instead of a BytesIO, an httpx.Response instead of requests.Response, a file opened in text mode ('r'), or an arbitrary object like a dict or Path-like custom class that is not pathlib.Path.","commonSituations":"Mixing HTTP libraries (using httpx or aiohttp responses), reading a file with open(path, 'r') before passing it, or assuming convert() accepts byte content directly.","solutions":["Wrap raw bytes: md.convert(io.BytesIO(data), stream_info=StreamInfo(extension='.pdf', mimetype='application/pdf'))","For other HTTP clients, pass the body: md.convert(io.BytesIO(resp.content)) or construct a requests.Response","Open files in binary mode: open(path, 'rb') or just pass the path string/Path","For text-mode handles, reopen in 'rb'"],"exampleFix":"# before\nwith open(\"a.pdf\", \"r\") as f:\n    md.convert(f)  # TypeError: TextIOBase rejected\nmd.convert(resp.content)  # TypeError: bytes rejected\n\n# after\nwith open(\"a.pdf\", \"rb\") as f:\n    md.convert(f)\nmd.convert(io.BytesIO(resp.content), stream_info=StreamInfo(extension=\".pdf\", mimetype=\"application/pdf\"))","handlingStrategy":"type-guard","validationCode":"import io, requests\nfrom pathlib import Path\n\ndef is_valid_source(s) -> bool:\n    return isinstance(s, (str, Path)) or isinstance(s, requests.Response) or (\n        hasattr(s, \"read\") and callable(s.read) and not isinstance(s, io.TextIOBase)\n    )\n\nassert is_valid_source(source)","typeGuard":"from __future__ import annotations\nimport io, requests\nfrom pathlib import Path\nfrom typing import Union\n\nValidSource = Union[str, Path, requests.Response, io.BufferedIOBase]\n\ndef is_valid_markitdown_source(source: object) -> TypeGuard[ValidSource]:\n    if isinstance(source, (str, Path)):\n        return True\n    if isinstance(source, requests.Response):\n        return True\n    return (\n        hasattr(source, \"read\")\n        and callable(source.read)\n        and not isinstance(source, io.TextIOBase)\n    )","tryCatchPattern":"try:\n    result = md.convert(source)\nexcept TypeError as e:\n    if \"Invalid source type\" in str(e):\n        source = io.BytesIO(source if isinstance(source, bytes) else bytes(source))\n        result = md.convert(source, stream_info=StreamInfo(extension=ext, mimetype=mime))\n    else:\n        raise","preventionTips":["Always open files with mode 'rb' before passing to convert()","Standardize on requests if you pass Response objects; otherwise pass resp.content via BytesIO","Type-annotate your call sites with the union of accepted source types"],"tags":["typeerror","api-misuse","dispatch"],"backgroundTag":null,"analyzedSha":"fd239d5d2be43d9b68329730206b9312c7d5a388","analyzedAt":"2026-08-14T15:47:51.745Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}