{"record":{"id":"0b9f927e4e6dd305","repo":"docling-project/docling","slug":"zip-urls-are-not-accepted-on-the-convert-endpoint","errorCode":null,"errorMessage":"ZIP URLs are not accepted on the convert endpoint","messagePattern":"ZIP URLs are not accepted on the convert endpoint","errorType":"http","errorClass":"ValueError","httpStatus":422,"severity":"error","filePath":"docling/datamodel/service/requests.py","lineNumber":57,"sourceCode":"\n\nclass FileSourceRequest(FileSource):\n    kind: Literal[\"file\"] = \"file\"\n\n\nclass AnyHttpSourceRequest(HttpSource):\n    kind: Literal[\"http\"] = \"http\"\n\n\nclass HttpSourceRequest(AnyHttpSourceRequest):\n    \"\"\"HTTP source for convert endpoints — rejects ZIP URLs.\"\"\"\n\n    @field_validator(\"url\")\n    @classmethod\n    def reject_zip_url(cls, value: AnyHttpUrl) -> AnyHttpUrl:\n        path = str(value).lower().split(\"?\", maxsplit=1)[0]\n        if path.endswith(\".zip\"):\n            raise ValueError(\"ZIP URLs are not accepted on the convert endpoint\")\n        return value\n\n\nclass S3SourceRequest(S3Coordinates):\n    kind: Literal[\"s3\"] = \"s3\"\n\n\nclass AzureBlobSourceRequest(AzureBlobCoordinates):\n    kind: Literal[\"azure_blob\"] = \"azure_blob\"\n\n\nclass GoogleCloudStorageSourceRequest(GoogleCloudStorageCoordinates):\n    kind: Literal[\"google_cloud_storage\"] = \"google_cloud_storage\"\n\n\nclass GoogleDriveSourceRequest(GoogleDriveCoordinates):\n    kind: Literal[\"google_drive\"] = \"google_drive\"\n","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/docling-project/docling/blob/61d76f1ff3f8428065465889f7b4577da7df704c/docling/datamodel/service/requests.py#L39-L75","documentation":"The HttpSourceRequest model used by the convert endpoints runs a field validator on url that rejects any HTTP URL whose path (case-insensitive, query string stripped) ends in '.zip'. The convert endpoint processes single documents, while ZIP archives are handled by a different flow (the service defines a zip target/response container), so ZIP URLs are refused at request validation time.","triggerScenarios":"Submitting a convert request whose http source url is e.g. 'https://example.com/docs/batch.ZIP' or '.../file.zip?token=abc'. The validator lowercases the URL and strips the query before checking the '.zip' suffix, so case tricks and query strings do not bypass it.","commonSituations":"Pointing the convert endpoint at a bulk-download ZIP of many documents; a CDN or export link that ends in .zip even for a single file; porting a curl example from the ZIP-ingest endpoint to the convert endpoint.","solutions":["Use the endpoint/flow that accepts ZIP archives instead of the convert endpoint.","If the ZIP contains one document, download and extract it client-side, then send the extracted file (or its extracted URL) to convert.","If the .zip suffix is incidental (URL rewrite), serve the file under a URL that reflects its real extension."],"exampleFix":"# before\nreq = {\n    \"sources\": [{\"kind\": \"http\", \"url\": \"https://cdn.example.com/batch.zip\"}],\n    \"options\": {...},\n}\n\n# after\n# extract locally, then convert each document\nwith zipfile.ZipFile(download(\"https://cdn.example.com/batch.zip\")) as zf:\n    for name in zf.namelist():\n        convert_bytes(zf.read(name))","handlingStrategy":"type-guard","validationCode":"from urllib.parse import urlparse\n\ndef is_zip_url(url: str) -> bool:\n    return urlparse(url).path.lower().endswith(\".zip\")\n\nif is_zip_url(source_url):\n    raise ValueError(\"convert endpoint rejects .zip URLs; use the ZIP ingest flow\")","typeGuard":"def is_convertible_http_url(url: str) -> bool:\n    return not urlparse(url).path.lower().endswith(\".zip\")","tryCatchPattern":"try:\n    resp = client.convert(sources=[{\"kind\": \"http\", \"url\": url}])\nexcept ValidationError as e:\n    if \"ZIP URLs\" in str(e):\n        # extract locally or switch to the ZIP-capable flow\n        ...\n    raise","preventionTips":["Filter or pre-download .zip links before submitting to convert.","Remember the check ignores query strings and URL case."],"tags":["http","validation","zip","convert-endpoint","service"],"backgroundTag":null,"analyzedSha":"61d76f1ff3f8428065465889f7b4577da7df704c","analyzedAt":"2026-08-14T23:53:18.727Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}