{"record":{"id":"0ed42a56d6e1d189","repo":"HKUDS/DeepTutor","slug":"source-source-id-not-found","errorCode":null,"errorMessage":"Source '{source_id}' not found","messagePattern":"Source '(.+?)' not found","errorType":"http","errorClass":"HTTPException","httpStatus":404,"severity":"warning","filePath":"deeptutor/api/routers/knowledge.py","lineNumber":3408,"sourceCode":"@router.get(\"/{kb_name}/github-sources\", response_model=list[GitHubSourceInfo])\nasync def get_github_sources(kb_name: str):\n    try:\n        manager, resolved_name, _ = _writable_kb(kb_name)\n        return [GitHubSourceInfo(**s) for s in manager.get_github_sources(resolved_name)]\n    except HTTPException:\n        raise\n    except ValueError:\n        raise HTTPException(status_code=404, detail=f\"KB '{kb_name}' not found\")\n    except Exception as e:\n        raise HTTPException(status_code=500, detail=str(e))\n\n\n@router.delete(\"/{kb_name}/github-source/{source_id}\")\nasync def remove_github_source(kb_name: str, source_id: str):\n    try:\n        manager, resolved_name, _ = _writable_kb(kb_name)\n        if not manager.remove_github_source(resolved_name, source_id):\n            raise HTTPException(status_code=404, detail=f\"Source '{source_id}' not found\")\n        return {\"message\": \"Removed\", \"source_id\": source_id}\n    except HTTPException:\n        raise\n    except ValueError:\n        raise HTTPException(status_code=404, detail=f\"KB '{kb_name}' not found\")\n    except Exception as e:\n        raise HTTPException(status_code=500, detail=str(e))\n\n\n@router.post(\"/{kb_name}/sync-github\")\nasync def sync_github_sources(kb_name: str):\n    try:\n        manager, resolved_name, kb_base_dir = _writable_kb(kb_name)\n        sources = manager.get_github_sources(resolved_name)\n        if not sources:\n            return {\"message\": \"No GitHub sources\", \"results\": []}\n        from deeptutor.services.github_source.sync import sync_source\n","sourceCodeStart":3390,"sourceCodeEnd":3426,"githubUrl":"https://github.com/HKUDS/DeepTutor/blob/3e82f130422a813cdd73c10b21a44e9325f5821a/deeptutor/api/routers/knowledge.py#L3390-L3426","documentation":"HTTP 404 from DELETE /{kb_name}/github-source/{source_id} when manager.remove_github_source returns falsy — no GitHub source with that id is registered on the KB.","triggerScenarios":"Removing a source_id that was already removed, belongs to another KB, or was never added; remove_github_source returns False/None.","commonSituations":"Duplicate remove clicks; stale sources list in the UI; source removed by a sync job concurrently.","solutions":["Refresh the GitHub sources list and confirm source_id is present","Treat 404 on remove as already-removed (idempotent) when appropriate","Update the UI to remove the row optimistically and ignore 404"],"exampleFix":"# before\nDELETE /kb/my-kb/github-source/src-9  -> 404 Source 'src-9' not found\n# after\nif resp.status_code == 404:\n    pass  # already removed; nothing to do","handlingStrategy":"try-catch","validationCode":"src_ids = {s['id'] for s in client.get(f'/api/v1/knowledge/{kb}/github-sources').json()}\nif source_id not in src_ids: return","typeGuard":null,"tryCatchPattern":"try:\n    client.delete(f'/api/v1/knowledge/{kb}/github-source/{source_id}')\nexcept HTTPError as e:\n    if e.response.status_code == 404 and \"Source\" in e.response.json()['detail']:\n        pass  # already removed\n    else: raise","preventionTips":["Make remove actions idempotent client-side","Remove the row from UI state immediately to prevent double submits","Refresh the sources list before showing remove buttons"],"tags":["github-source","http-404","idempotency","knowledge-base"],"backgroundTag":"resource-not-found","analyzedSha":"3e82f130422a813cdd73c10b21a44e9325f5821a","analyzedAt":"2026-08-27T06:57:25.364Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}