microsoft/markitdown · error · TypeError
Invalid source type: {type(source)}. Expected str, requests.
Error message
Invalid source type: {type(source)}. Expected str, requests.Response, BinaryIO. What it means
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.
Source
Thrown at packages/markitdown/src/markitdown/_markitdown.py:321
return self.convert_uri(source, stream_info=stream_info, **_kwargs)
else:
return self.convert_local(source, stream_info=stream_info, **kwargs)
# Path object
elif isinstance(source, Path):
return self.convert_local(source, stream_info=stream_info, **kwargs)
# Request response
elif isinstance(source, requests.Response):
return self.convert_response(source, stream_info=stream_info, **kwargs)
# Binary stream
elif (
hasattr(source, "read")
and callable(source.read)
and not isinstance(source, io.TextIOBase)
):
return self.convert_stream(source, stream_info=stream_info, **kwargs)
else:
raise TypeError(
f"Invalid source type: {type(source)}. Expected str, requests.Response, BinaryIO."
)
def convert_local(
self,
path: Union[str, Path],
*,
stream_info: Optional[StreamInfo] = None,
file_extension: Optional[str] = None, # Deprecated -- use stream_info
url: Optional[str] = None, # Deprecated -- use stream_info
**kwargs: Any,
) -> DocumentConverterResult:
if isinstance(path, Path):
path = str(path)
# Build a base StreamInfo object from which to start guesses
base_guess = StreamInfo(
local_path=path,View on GitHub (pinned to fd239d5d2b)
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'
Example fix
# before
with open("a.pdf", "r") as f:
md.convert(f) # TypeError: TextIOBase rejected
md.convert(resp.content) # TypeError: bytes rejected
# after
with open("a.pdf", "rb") as f:
md.convert(f)
md.convert(io.BytesIO(resp.content), stream_info=StreamInfo(extension=".pdf", mimetype="application/pdf")) Defensive patterns
Strategy: type-guard
Validate before calling
import io, requests
from pathlib import Path
def is_valid_source(s) -> bool:
return isinstance(s, (str, Path)) or isinstance(s, requests.Response) or (
hasattr(s, "read") and callable(s.read) and not isinstance(s, io.TextIOBase)
)
assert is_valid_source(source) Type guard
from __future__ import annotations
import io, requests
from pathlib import Path
from typing import Union
ValidSource = Union[str, Path, requests.Response, io.BufferedIOBase]
def is_valid_markitdown_source(source: object) -> TypeGuard[ValidSource]:
if isinstance(source, (str, Path)):
return True
if isinstance(source, requests.Response):
return True
return (
hasattr(source, "read")
and callable(source.read)
and not isinstance(source, io.TextIOBase)
) Try / catch
try:
result = md.convert(source)
except TypeError as e:
if "Invalid source type" in str(e):
source = io.BytesIO(source if isinstance(source, bytes) else bytes(source))
result = md.convert(source, stream_info=StreamInfo(extension=ext, mimetype=mime))
else:
raise Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
AI-assisted analysis of microsoft/markitdown@fd239d5d2b (2026-08-14).
Data as JSON: /api/errors/9870fbc680d42878.
Report an issue: GitHub.