{"record":{"id":"e7e35df5ffbcbaba","repo":"HKUDS/DeepTutor","slug":"at-least-one-url-is-required-e7e35d","errorCode":null,"errorMessage":"At least one URL is required.","messagePattern":"At least one URL is required\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"deeptutor/services/rag/pipelines/ima/client.py","lineNumber":222,"sourceCode":"            timeout=self._timeout,\n            transport=self._transport,\n        )\n\n    # ----- writing --------------------------------------------------------\n\n    async def import_urls(self, urls: list[str], *, folder_id: str = \"\") -> list[ImaImportedUrl]:\n        \"\"\"Add up to :data:`MAX_IMPORT_URLS` web pages to the bound library.\n\n        IMA reports a per-URL verdict rather than failing the batch, so partial\n        success is normal and is returned as-is for the caller to report.\n        \"\"\"\n        cleaned: list[str] = []\n        for raw in urls:\n            url = str(raw or \"\").strip()\n            if url and url not in cleaned:\n                cleaned.append(url)\n        if not cleaned:\n            raise ValueError(\"At least one URL is required.\")\n        if len(cleaned) > MAX_IMPORT_URLS:\n            raise ValueError(f\"IMA accepts at most {MAX_IMPORT_URLS} URLs per call.\")\n\n        # ``folder_id`` is required here, and the root folder's id is the\n        # knowledge base id itself.\n        target = str(folder_id or \"\").strip() or self._config.knowledge_base_id\n        data = await self._wire.post(\n            \"import_urls\",\n            {\n                \"urls\": cleaned,\n                \"knowledge_base_id\": self._config.knowledge_base_id,\n                \"folder_id\": target,\n            },\n        )\n        results = parse_imported_urls(data)\n        if results:\n            return results\n        # Some responses acknowledge the batch without echoing per-URL rows.","sourceCodeStart":204,"sourceCodeEnd":240,"githubUrl":"https://github.com/HKUDS/DeepTutor/blob/3e82f130422a813cdd73c10b21a44e9325f5821a/deeptutor/services/rag/pipelines/ima/client.py#L204-L240","documentation":"ValueError from IMA client import_urls: after stripping and deduplicating the input URL list, no valid URL remains. The IMA (Ingestion/Multimodal Archive) pipeline requires at least one URL per import call.","triggerScenarios":"Calling the IMA run pipeline with an empty urls list, or a list of empty/whitespace-only strings; all entries falsy after str().strip().","commonSituations":"Frontend sending an empty array when the user submits without entering URLs; upstream scraping step producing empty strings; passing None inside the list.","solutions":["Validate and filter URLs client-side before calling import_urls; require at least one non-empty entry.","Fix the upstream producer that builds the URL list.","Retry the pipeline with actual URLs supplied."],"exampleFix":"# before\nurls = [\"\", \"  \"]\nawait client.import_urls(folder_id, urls)\n# after\nurls = [u for u in raw_urls if u and u.strip()]\nif not urls: raise ValueError(\"no urls\")\nawait client.import_urls(folder_id, urls)","handlingStrategy":"validation","validationCode":"cleaned = [u for u in (str(r or \"\").strip() for r in urls) if u]\nif not cleaned:\n    raise InputError(\"at least one URL required\")","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Disable submit in the UI until at least one non-empty URL is entered."],"tags":["ima","input-validation","urls"],"backgroundTag":"empty-input-list","analyzedSha":"3e82f130422a813cdd73c10b21a44e9325f5821a","analyzedAt":"2026-08-27T06:57:25.364Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}