{"record":{"id":"27271f7f6b91255c","repo":"HKUDS/DeepTutor","slug":"unknown-agent-kind-kind-r","errorCode":null,"errorMessage":"Unknown agent kind: {kind!r}","messagePattern":"Unknown agent kind: (.+?)","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"deeptutor/api/routers/subagents.py","lineNumber":92,"sourceCode":"\n    options = await list_backend_options()\n    return {\"backends\": [o.to_dict() for o in options]}\n\n\n@router.post(\"/backends/{kind}/sync\")\nasync def sync_backend(kind: str):\n    \"\"\"Re-pull one backend's model catalog (the settings \"sync\" button).\n\n    For Claude Code this scrapes its ``/model`` TUI live and caches the result;\n    for Codex it re-reads the CLI-maintained cache.\n    \"\"\"\n    from deeptutor.services.subagent import get_backend\n    from deeptutor.services.subagent.models import sync_backend_options\n\n    backend = get_backend(kind)\n    if backend is None or not getattr(backend, \"local_cli\", True):\n        # Only local CLIs have a model catalog to sync; partners run their own.\n        raise HTTPException(status_code=400, detail=f\"Unknown agent kind: {kind!r}\")\n    options = await sync_backend_options(kind)\n    return options.to_dict()\n\n\n@router.get(\"/partners\")\nasync def list_visible_partners():\n    \"\"\"Partners the current user can connect & consult.\n\n    Returns every partner for an admin, or just the ones an admin has assigned\n    for a non-admin. The partner CRUD API (``/api/v1/partners``) stays fully\n    admin-gated; this is the read surface the connect flow and the partner list\n    page use, so a non-admin sees their assigned partners without a 403.\n    \"\"\"\n    return {\"partners\": visible_partner_cards()}\n\n\n@router.get(\"/connections\")\nasync def list_connections():","sourceCodeStart":74,"sourceCodeEnd":110,"githubUrl":"https://github.com/HKUDS/DeepTutor/blob/3e82f130422a813cdd73c10b21a44e9325f5821a/deeptutor/api/routers/subagents.py#L74-L110","documentation":"Raised by the subagent model-sync endpoint when the requested agent kind has no registered backend, or the backend is not a local CLI (partners run their own model catalog). Only local CLI subagents expose a model catalog that DeepTutor can sync.","triggerScenarios":"GET/POST on the sync_backend route with a kind string that is not in the subagent backend registry, or a kind whose backend object lacks local_cli=True (e.g. the partner backend).","commonSituations":"Frontend sends a stale or misspelled kind after renaming/removing a backend; calling sync on a partner-kind agent; backend registry not registering a newly added CLI backend.","solutions":["Verify the kind via GET listing of backend kinds before calling sync","Ensure you are syncing a local CLI backend, not the partner backend","Register/fix the backend kind in deeptutor.services.subagent so get_backend(kind) returns a local CLI backend"],"exampleFix":"// before\nGET /api/v1/subagents/sync/claude_codex_typo\n// after\nGET /api/v1/subagents/sync/claude-code   // exact kind from list_backend_kinds()","handlingStrategy":"validation","validationCode":"const kinds = await (await fetch('/api/v1/subagents/backends')).json();\nif (!kinds.includes(kind) ) throw new Error('invalid kind');\nif (kind === 'partner') throw new Error('partners cannot sync models');","typeGuard":"const isSyncableKind = (k: string, kinds: string[]) =>\n  kinds.includes(k) && k !== 'partner';","tryCatchPattern":"try { await syncBackend(kind); } catch (e) { if (e.status === 400) refreshKinds(); else throw e; }","preventionTips":["Populate kind dropdowns from the backends list endpoint","Disable sync UI for partner-kind connections"],"tags":["http-400","subagent","backend-registry","api"],"backgroundTag":"invalid-request-parameter","analyzedSha":"3e82f130422a813cdd73c10b21a44e9325f5821a","analyzedAt":"2026-08-27T06:57:25.364Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}