{"record":{"id":"ad491cc1940a66c4","repo":"HKUDS/DeepTutor","slug":"partner-is-not-assigned-to-you","errorCode":null,"errorMessage":"Partner is not assigned to you","messagePattern":"Partner is not assigned to you","errorType":"http","errorClass":"HTTPException","httpStatus":403,"severity":"error","filePath":"deeptutor/multi_user/partner_access.py","lineNumber":91,"sourceCode":"    \"\"\"Whether the user may talk to *partner_id* — manage it, or be assigned it.\"\"\"\n    actor = user or get_current_user()\n    if can_manage_partner(partner_id, actor):\n        return True\n    return str(partner_id or \"\").strip() in assigned_partner_ids(actor.id)\n\n\ndef assert_partner_allowed(partner_id: str, user_id: str | None = None) -> None:\n    \"\"\"Raise 403 unless the current user may talk to *partner_id*.\n\n    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\",","sourceCodeStart":73,"sourceCodeEnd":109,"githubUrl":"https://github.com/HKUDS/DeepTutor/blob/3e82f130422a813cdd73c10b21a44e9325f5821a/deeptutor/multi_user/partner_access.py#L73-L109","documentation":"HTTP 403 from assert_partner_allowed: the current user can neither manage the partner (can_manage_partner) nor is the partner id in their assigned_partner_ids. Guards every partner usage (execute, connect, consult).","triggerScenarios":"Calling a partner endpoint with a partner_id owned by someone else without an assignment; using a revoked partner after grants changed; wrong partner id copied from another workspace.","commonSituations":"Partner sharing across team members; stale frontend state after an admin revoked assignment; integration tests hitting unassigned partners.","solutions":["Verify the partner id appears in the user's assigned partner list before use","Request assignment from the partner owner/admin","Refresh partner list after grant changes to drop stale ids"],"exampleFix":"// before\nassert_partner_allowed(\"partner-123\")  # 403\n\n// after\nfrom deeptutor.multi_user.partner_access import assigned_partner_ids\npid = \"partner-123\"\nassert pid in assigned_partner_ids(user.id) or can_manage_partner(pid, user), \"not yours\"\nassert_partner_allowed(pid)","handlingStrategy":"validation","validationCode":"from deeptutor.multi_user.partner_access import can_manage_partner, assigned_partner_ids\nif not (can_manage_partner(pid, get_current_user()) or pid in assigned_partner_ids(user.id)):\n    raise PartnerNotAvailable(pid)","typeGuard":"def partner_usable(pid: str, user) -> bool:\n    return can_manage_partner(pid, user) or pid in assigned_partner_ids(user.id)","tryCatchPattern":"try:\n    assert_partner_allowed(pid)\nexcept HTTPException as e:\n    if e.status_code == 403:\n        refresh_partner_list()  # grants may have changed; resync","preventionTips":["Render partner menus from the user's assigned partner list","Refresh partner lists after grant/assignment changes","Never hardcode partner ids across user contexts"],"tags":["partner","permissions","http-403","multi-user"],"backgroundTag":"insufficient-permissions","analyzedSha":"3e82f130422a813cdd73c10b21a44e9325f5821a","analyzedAt":"2026-08-27T06:57:25.364Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}