{"record":{"id":"0ac7214eeae46187","repo":"HKUDS/DeepTutor","slug":"both-name-and-agent-kind-are-required","errorCode":null,"errorMessage":"Both name and agent_kind are required.","messagePattern":"Both name and agent_kind are required\\.","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"deeptutor/api/routers/subagents.py","lineNumber":144,"sourceCode":"                \"updated_at\": meta.get(\"updated_at\"),\n            }\n        )\n    return {\"connections\": connections}\n\n\n@router.post(\"/connections\")\nasync def create_connection(payload: ConnectSubagentRequest):\n    \"\"\"Connect a subagent (a local CLI, or one of the user's partners) as a selectable KB.\n\n    A partner connection (``agent_kind == \"partner\"``) binds a ``partner_id``\n    instead of a working directory: consulting it opens a fresh session on that\n    partner, exactly as if the user started one from the partner page. Every\n    consult within one DeepTutor chat lands in that one partner session.\n    \"\"\"\n    name = (payload.name or \"\").strip()\n    agent_kind = (payload.agent_kind or \"\").strip()\n    if not name or not agent_kind:\n        raise HTTPException(status_code=400, detail=\"Both name and agent_kind are required.\")\n    if agent_kind not in list_backend_kinds():\n        raise HTTPException(status_code=400, detail=f\"Unknown agent kind: {agent_kind!r}\")\n\n    resolved_cwd = \"\"\n    partner_id = \"\"\n    if agent_kind == PARTNER_BACKEND_KIND:\n        partner_id = (payload.partner_id or \"\").strip()\n        if not partner_id:\n            raise HTTPException(\n                status_code=400, detail=\"A partner_id is required to connect a partner.\"\n            )\n        # Partners are admin-managed, but an admin can assign one to a user via\n        # the grant system. An admin may connect any partner; a non-admin only a\n        # partner assigned to them (403 otherwise). The partner still runs in its\n        # own isolated scope — connecting just lets the user consult it in chat.\n        assert_partner_allowed(partner_id)\n        from deeptutor.services.partners import get_partner_manager\n","sourceCodeStart":126,"sourceCodeEnd":162,"githubUrl":"https://github.com/HKUDS/DeepTutor/blob/3e82f130422a813cdd73c10b21a44e9325f5821a/deeptutor/api/routers/subagents.py#L126-L162","documentation":"The create-connection endpoint requires both a non-empty name and agent_kind in the JSON payload; whitespace-only or missing values are rejected with 400 before any backend lookup.","triggerScenarios":"POST /connections with {\"name\":\"\"}, {\"agent_kind\":\" \"}, or either field omitted/null.","commonSituations":"Frontend form submitted before user fills both fields; whitespace sneaking in from a trimmed-elsewhere input; payload built with undefined JS variables.","solutions":["Fill both name and agent_kind with non-blank values","Trim inputs client-side before POST","Check the request payload actually serializes both fields"],"exampleFix":"// before\n{\"name\": \"  \", \"agent_kind\": \"opencode\"}\n// after\n{\"name\": \"my-agent\", \"agent_kind\": \"opencode\"}","handlingStrategy":"validation","validationCode":"const name = rawName.trim();\nconst kind = rawKind.trim();\nif (!name || !kind) return; // don't send\nawait fetch('/connections', {method:'POST', body: JSON.stringify({name, agent_kind: kind})});","typeGuard":"const isValidConnectionPayload = (p: any): p is {name:string; agent_kind:string} =>\n  typeof p?.name === 'string' && p.name.trim() !== '' &&\n  typeof p?.agent_kind === 'string' && p.agent_kind.trim() !== '';","tryCatchPattern":"try { await createConnection(p); } catch (e) { if (e.status === 400) showFormError(e.detail); }","preventionTips":["Require both fields in the form before enabling submit","Trim inputs client-side"],"tags":["http-400","validation","subagent","api"],"backgroundTag":"missing-required-field","analyzedSha":"3e82f130422a813cdd73c10b21a44e9325f5821a","analyzedAt":"2026-08-27T06:57:25.364Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}