{"record":{"id":"7cc45e125c0973c4","repo":"microsoft/markitdown","slug":"not-a-data-uri","errorCode":null,"errorMessage":"Not a data URI","messagePattern":"Not a data URI","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"packages/markitdown/src/markitdown/_uri_utils.py","lineNumber":21,"sourceCode":"from typing import Tuple, Dict\nfrom urllib.request import url2pathname\nfrom urllib.parse import urlparse, unquote_to_bytes\n\n\ndef file_uri_to_path(file_uri: str) -> Tuple[str | None, str]:\n    \"\"\"Convert a file URI to a local file path\"\"\"\n    parsed = urlparse(file_uri)\n    if parsed.scheme != \"file\":\n        raise ValueError(f\"Not a file URL: {file_uri}\")\n\n    netloc = parsed.netloc if parsed.netloc else None\n    path = os.path.abspath(url2pathname(parsed.path))\n    return netloc, path\n\n\ndef parse_data_uri(uri: str) -> Tuple[str | None, Dict[str, str], bytes]:\n    if not uri.startswith(\"data:\"):\n        raise ValueError(\"Not a data URI\")\n\n    header, _, data = uri.partition(\",\")\n    if not _:\n        raise ValueError(\"Malformed data URI, missing ',' separator\")\n\n    meta = header[5:]  # Strip 'data:'\n    parts = meta.split(\";\")\n\n    is_base64 = False\n    # Ends with base64?\n    if parts[-1] == \"base64\":\n        parts.pop()\n        is_base64 = True\n\n    mime_type = None  # Normally this would default to text/plain but we won't assume\n    if len(parts) and len(parts[0]) > 0:\n        # First part is the mime type\n        mime_type = parts.pop(0)","sourceCodeStart":3,"sourceCodeEnd":39,"githubUrl":"https://github.com/microsoft/markitdown/blob/fd239d5d2be43d9b68329730206b9312c7d5a388/packages/markitdown/src/markitdown/_uri_utils.py#L3-L39","documentation":"parse_data_uri() guards its contract: the input must literally start with 'data:' or it raises this bare ValueError. convert_uri() only invokes it after a startswith('data:') check, so the error surfaces only for direct calls on non-data URIs.","triggerScenarios":"Calling parse_data_uri('file:///x') or parse_data_uri('text/plain;base64,AAA') (missing data: prefix) directly.","commonSituations":"Custom preprocessing that strips or mangles the scheme, or routing logic that forwards URIs to the wrong parser.","solutions":["Prefix the payload with 'data:' before parsing","Route by scheme (startswith('data:')) before choosing parse_data_uri","Prefer the public md.convert_uri(), which routes correctly"],"exampleFix":"# before\nparse_data_uri(\"text/plain;base64,aGVsbG8=\")  # ValueError\n\n# after\nparse_data_uri(\"data:text/plain;base64,aGVsbG8=\")","handlingStrategy":"validation","validationCode":"assert uri.startswith(\"data:\")","typeGuard":null,"tryCatchPattern":"from markitdown._uri_utils import parse_data_uri\n\ntry:\n    mime, attrs, data = parse_data_uri(uri)\nexcept ValueError as e:\n    if \"Not a data URI\" in str(e):\n        uri = \"data:\" + uri.lstrip(\"data:\")  # normalize then retry once\n        mime, attrs, data = parse_data_uri(uri)\n    else:\n        raise","preventionTips":["Validate the data: prefix at URI-ingestion boundaries","Use convert_uri() for routing rather than calling parse_data_uri directly"],"tags":["uri","data-uri","internal-util"],"backgroundTag":null,"analyzedSha":"fd239d5d2be43d9b68329730206b9312c7d5a388","analyzedAt":"2026-08-14T15:47:51.745Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}