{"record":{"id":"3e74a53b83989e7b","repo":"HKUDS/DeepTutor","slug":"you-cannot-manage-this-partner","errorCode":null,"errorMessage":"You cannot manage this partner","messagePattern":"You cannot manage this partner","errorType":"http","errorClass":"HTTPException","httpStatus":403,"severity":"error","filePath":"deeptutor/multi_user/partner_access.py","lineNumber":101,"sourceCode":"    A no-op for admins, for the partner's owner, and for single-user\n    deployments (where the current user resolves to the local admin).\n    \"\"\"\n    user = get_current_user()\n    if can_manage_partner(partner_id, user):\n        return\n    if str(partner_id or \"\").strip() in assigned_partner_ids(user_id or user.id):\n        return\n    raise HTTPException(status_code=403, detail=\"Partner is not assigned to you\")\n\n\ndef assert_partner_manageable(partner_id: str) -> None:\n    \"\"\"Raise 403 unless the current user may configure *partner_id*.\n\n    Deliberately the same 403 an unassigned partner gets: someone who may only\n    talk to a partner learns nothing new about who owns it.\n    \"\"\"\n    if not can_manage_partner(partner_id):\n        raise HTTPException(status_code=403, detail=\"You cannot manage this partner\")\n\n\n# Identity-only card fields a consumer needs (partner list page, connect modal).\n# Deliberately excludes channels / llm_selection / tool config so a user who was\n# merely *assigned* a partner sees its face, never its wiring.\n_CARD_FIELDS = (\n    \"partner_id\",\n    \"name\",\n    \"description\",\n    \"emoji\",\n    \"color\",\n    \"avatar\",\n    \"language\",\n    \"running\",\n)\n\n\ndef identity_card(partner: dict[str, Any]) -> dict[str, Any]:","sourceCodeStart":83,"sourceCodeEnd":119,"githubUrl":"https://github.com/HKUDS/DeepTutor/blob/3e82f130422a813cdd73c10b21a44e9325f5821a/deeptutor/multi_user/partner_access.py#L83-L119","documentation":"HTTP 403 from assert_partner_manageable: can_manage_partner(partner_id) returned False, meaning the current user (non-admin, non-owner) tried to configure a partner. Deliberately the same 403 as usage denial so ownership is not leaked.","triggerScenarios":"Calling partner configuration endpoints (edit channels, llm_selection, tool config) for a partner the user was merely assigned to or that someone else owns; non-admin attempting partner CRUD on another user's partner.","commonSituations":"Assigned users trying to tweak wiring of a shared partner; UI showing manage controls to non-owners.","solutions":["Have the partner owner or an admin make the configuration change","Check is_admin / ownership before showing manage controls in the UI","Use read-only card fields (_CARD_FIELDS) for assigned users"],"exampleFix":"// before\nassert_partner_manageable(\"partner-123\")  # 403 for assigned-only user\n\n// after\nfrom deeptutor.multi_user.partner_access import can_manage_partner\nif not can_manage_partner(\"partner-123\"):\n    raise HTTPException(403, \"Ask the owner to update this partner\")\nassert_partner_manageable(\"partner-123\")","handlingStrategy":"validation","validationCode":"from deeptutor.multi_user.partner_access import can_manage_partner\nif not can_manage_partner(pid):\n    raise NotOwner(pid)  # hide manage UI for this partner","typeGuard":"def can_configure(pid: str) -> bool:\n    return can_manage_partner(pid)","tryCatchPattern":"try:\n    assert_partner_manageable(pid)\nexcept HTTPException as e:\n    if e.status_code == 403:\n        raise ManageForbidden(pid) from e","preventionTips":["Gate manage/config screens on can_manage_partner before rendering","Show assigned users identity-only card fields, never wiring controls","Route config changes through the owner or an admin"],"tags":["partner","permissions","http-403","ownership"],"backgroundTag":"insufficient-permissions","analyzedSha":"3e82f130422a813cdd73c10b21a44e9325f5821a","analyzedAt":"2026-08-27T06:57:25.364Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}