{"record":{"id":"3508228f2f057b0f","repo":"HKUDS/DeepTutor","slug":"knowledge-base-kb-name-is-connected-to-an-exte","errorCode":null,"errorMessage":"Knowledge base '{kb_name}' is connected to an external resource and is read-only. Local file operations and re-indexing are not available for it.","messagePattern":"Knowledge base '(.+?)' is connected to an external resource and is read-only\\. Local file operations and re-indexing are not available for it\\.","errorType":"http","errorClass":"HTTPException","httpStatus":409,"severity":"error","filePath":"deeptutor/api/routers/knowledge.py","lineNumber":789,"sourceCode":"    raise HTTPException(status_code=404, detail=f\"Knowledge base '{requested}' not found\")\n\n\ndef _load_kb_entry_or_404(manager: KnowledgeBaseManager, kb_name: str) -> dict:\n    manager.config = manager._load_config()\n    kb_entry = manager.config.get(\"knowledge_bases\", {}).get(kb_name)\n    if kb_entry is None:\n        raise HTTPException(status_code=404, detail=f\"Knowledge base '{kb_name}' not found\")\n    return kb_entry\n\n\ndef _assert_not_connected_kb(kb_name: str, kb_entry: dict) -> None:\n    \"\"\"Block writes to connected KBs (Obsidian vaults, linked indexes).\n\n    They are read-only pointers to the user's external files — we never write\n    into or re-index them.\n    \"\"\"\n    if is_connected_kb(kb_entry):\n        raise HTTPException(\n            status_code=409,\n            detail=(\n                f\"Knowledge base '{kb_name}' is connected to an external resource and is \"\n                \"read-only. Local file operations and re-indexing are not available for it.\"\n            ),\n        )\n\n\ndef _assert_kb_writable_or_409(kb_name: str, kb_entry: dict) -> None:\n    _assert_not_connected_kb(kb_name, kb_entry)\n    if bool(kb_entry.get(\"needs_reindex\", False)):\n        raise HTTPException(\n            status_code=409,\n            detail=(\n                f\"Knowledge base '{kb_name}' uses legacy index format and needs reindex \"\n                \"before accepting incremental uploads.\"\n            ),\n        )","sourceCodeStart":771,"sourceCodeEnd":807,"githubUrl":"https://github.com/HKUDS/DeepTutor/blob/3e82f130422a813cdd73c10b21a44e9325f5821a/deeptutor/api/routers/knowledge.py#L771-L807","documentation":"Raised by _assert_not_connected_kb when is_connected_kb(kb_entry) is true — the KB is a read-only pointer to an external resource (e.g. an Obsidian vault or linked external index). Writes and re-indexing are deliberately forbidden; HTTP 409.","triggerScenarios":"Attempting folder creation, file move/delete, upload, or reindex on a connected/linked KB instead of a local one.","commonSituations":"User links an Obsidian vault then tries to upload into it from the Files UI; automation scripts iterating all KBs and applying write operations indiscriminately.","solutions":["Write to a local (non-connected) KB instead","If ingestion is needed, copy the external files into a local KB","Re-index the source externally (for vaults, let the external tool manage it)"],"exampleFix":"# before\nupload_files(kb='my-obsidian-vault', ...)\n# after\nupload_files(kb='local-kb', ...)","handlingStrategy":"type-guard","validationCode":"from deeptutor.api.routers.knowledge import is_connected_kb\nif is_connected_kb(kb_entry): block_write_ui(kb_name)","typeGuard":"def is_writable_kb(kb_entry: dict) -> bool:\n    return not is_connected_kb(kb_entry) and not kb_entry.get('needs_reindex', False)","tryCatchPattern":null,"preventionTips":["Mark connected KBs as read-only in the UI","Route write operations only to local KBs","Handle 409 read-only responses by redirecting users to a local KB"],"tags":["knowledge-base","read-only","connected-kb","http-409"],"backgroundTag":"read-only-resource","analyzedSha":"3e82f130422a813cdd73c10b21a44e9325f5821a","analyzedAt":"2026-08-27T06:57:25.364Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}