microsoft/markitdown · error · ValueError

Unsupported URI scheme: {uri.split(':')[0]}. Supported schem

Error message

Unsupported URI scheme: {uri.split(':')[0]}. Supported schemes are: file:, data:, http:, https:

What it means

convert_uri() only handles four schemes: file:, data:, http:, https:. Any other scheme falls through to a ValueError that echoes the scheme prefix (everything before the first colon). This is a fast-fail guard so unsupported protocols (ftp:, s3:, mailto:, blob:) never reach network or filesystem code.

Source

Thrown at packages/markitdown/src/markitdown/_markitdown.py:485

                io.BytesIO(data),
                stream_info=base_guess,
                file_extension=file_extension,
                url=mock_url,
                **kwargs,
            )
        # HTTP/HTTPS URIs
        elif uri.startswith("http:") or uri.startswith("https:"):
            response = self._requests_session.get(uri, stream=True)
            response.raise_for_status()
            return self.convert_response(
                response,
                stream_info=stream_info,
                file_extension=file_extension,
                url=mock_url,
                **kwargs,
            )
        else:
            raise ValueError(
                f"Unsupported URI scheme: {uri.split(':')[0]}. Supported schemes are: file:, data:, http:, https:"
            )

    def convert_response(
        self,
        response: requests.Response,
        *,
        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 there is a content-type header, get the mimetype and charset (if present)
        mimetype: Optional[str] = None
        charset: Optional[str] = None

        if "content-type" in response.headers:
            parts = response.headers["content-type"].split(";")

View on GitHub (pinned to fd239d5d2b)

Solutions

  1. Download non-HTTP resources first, then pass the local path or a BytesIO stream
  2. For Windows paths, pass them as plain paths to convert(), not to convert_uri()
  3. Prefix valid web URIs with http:// or https:// explicitly

Example fix

# before
md.convert_uri("s3://bucket/doc.pdf")  # ValueError: Unsupported URI scheme: s3

# after
import boto3, io
body = boto3.client("s3").get_object(Bucket="bucket", Key="doc.pdf")["Body"].read()
md.convert(io.BytesIO(body), stream_info=StreamInfo(extension=".pdf", mimetype="application/pdf"))
Defensive patterns

Strategy: validation

Validate before calling

SUPPORTED_SCHEMES = ("file:", "data:", "http:", "https:")

def is_supported_uri(uri: str) -> bool:
    return uri.startswith(SUPPORTED_SCHEMES)

Try / catch

try:
    result = md.convert_uri(uri)
except ValueError as e:
    if "Unsupported URI scheme" in str(e):
        # fetch via the right client, then convert the bytes
        raise
    raise

Prevention

When it happens

Trigger: md.convert_uri('ftp://host/file.pdf'), md.convert_uri('s3://bucket/key.docx'), md.convert_uri('mailto:a@b.com'), or a relative string without any scheme (split(':')[0] then yields the whole first token).

Common situations: Passing cloud-storage URIs (s3://, gs://, abfs://) or Windows drive paths ('C:\file.docx', where 'C' is reported as the scheme) instead of local paths or HTTP URLs.

Related errors


AI-assisted analysis of microsoft/markitdown@fd239d5d2b (2026-08-14). Data as JSON: /api/errors/4946f9b8dec6c5be. Report an issue: GitHub.