{"record":{"id":"66bd8e0ea1072e23","repo":"BerriAI/litellm","slug":"no-team-found-in-token-checked-team-id-field-te","errorCode":null,"errorMessage":"No team found in token. Checked team_id field '{team_id_field}' and team_alias field '{team_alias_field}'.{hint}","messagePattern":"No team found in token\\. Checked team_id field '(.+?)' and team_alias field '(.+?)'\\.(.+?)","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"litellm/proxy/auth/handle_jwt.py","lineNumber":1285,"sourceCode":"                    parts: Final = team_id_field.rsplit(\".\", 1)\n                    if parts[-1].isdigit():\n                        base_field = parts[0]\n                        hint = (\n                            f\" Hint: dot-notation array indexing (e.g. '{team_id_field}') is not \"\n                            f\"supported. Use '{base_field}' instead — LiteLLM automatically \"\n                            f\"uses the first element when the field value is a list.\"\n                        )\n                # \"roles[0]\" — bracket-notation indexing is also not supported in get_nested_value\n                elif \"[\" in team_id_field and team_id_field.endswith(\"]\"):\n                    m: Final = re.match(r\"^(\\w+)\\[(\\d+)\\]$\", team_id_field)\n                    if m:\n                        base_field = m.group(1)\n                        hint = (\n                            f\" Hint: array indexing (e.g. '{team_id_field}') is not supported \"\n                            f\"in team_id_jwt_field. Use '{base_field}' instead — LiteLLM \"\n                            f\"automatically uses the first element when the field value is a list.\"\n                        )\n            raise Exception(\n                f\"No team found in token. Checked team_id field '{team_id_field}' and team_alias field '{team_alias_field}'.{hint}\"\n            )\n\n        return individual_team_id, team_object\n\n    @staticmethod\n    def get_all_team_ids(jwt_handler: JWTHandler, jwt_valid_token: dict) -> set[str]:\n        \"\"\"Get combined team IDs from groups and individual team_id\"\"\"\n        team_ids_from_groups: Final = jwt_handler.get_team_ids_from_jwt(token=jwt_valid_token)\n\n        all_team_ids: Final = set(team_ids_from_groups)\n\n        return all_team_ids\n\n    @staticmethod\n    def _team_has_passthrough_route_access(\n        team_object: LiteLLM_TeamTable | None,\n        route: str,","sourceCodeStart":1267,"sourceCodeEnd":1303,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/proxy/auth/handle_jwt.py#L1267-L1303","documentation":"JWT auth tried to resolve a team from the token using `team_id_jwt_field` (and `team_alias_jwt_field`) and found nothing usable in either. The trailing hint (when present) explains a known pitfall: get_nested_value does not support dot-index ('roles.0') or bracket ('roles[0]') access — if the claim is a list, configure the bare field name and LiteLLM takes the first element.","triggerScenarios":"`team_id_jwt_field` set to a claim that doesn't exist in the token (e.g. 'client_id' for Azure AD tokens that use 'roles' or 'tid'). Field configured as 'roles[0]' or 'groups.0'. Claim exists but is null/empty. Nested path like 'tenant.team_id' where the parent key differs.","commonSituations":"Switching IdPs (Okta -> Azure AD) without updating team_id_jwt_field. Azure AD tokens where team info lives in the array-valued 'roles' or 'groups' claim — developers naturally write 'roles[0]' which is unsupported. Testing with tokens generated by jwt.io without the expected claims.","solutions":["Decode the JWT and find the actual claim holding the team/group id; set `team_id_jwt_field` to that exact name (dot-paths like 'tenant.team_id' are supported).","If the claim is a list (e.g. Azure 'roles'), set the bare field name ('roles') — LiteLLM uses the first element; do NOT use 'roles[0]' or 'roles.0'.","If the token simply has no team claim, either remove team_id_jwt_field, use `team_id_default`, or enable fallback mechanisms.","For alias-based lookup, verify `team_alias_jwt_field` matches the claim carrying the team alias in the DB."],"exampleFix":"# config.yaml — before (Azure AD token with roles: [\"team-123\"])\nlitellm_jwtauth:\n  team_id_jwt_field: \"roles[0]\"\n\n# after\nlitellm_jwtauth:\n  team_id_jwt_field: \"roles\"","handlingStrategy":"validation","validationCode":"claims = jwt_claims(token)\nfield = CONFIG['litellm_jwtauth']['team_id_jwt_field']\nval = claims.get(field) if '.' not in field else nested_get(claims, field)\nif val is None or val == []:\n    raise ValueError(f'token lacks team claim {field!r}; fix team_id_jwt_field or IdP token')\nif isinstance(val, list) and not val:\n    raise ValueError('team claim is an empty list')","typeGuard":"def has_team_claim(claims: dict, field: str) -> bool:\n    v = claims\n    for part in field.split('.'):\n        if not isinstance(v, dict) or part not in v:\n            return False\n        v = v[part]\n    return bool(v) or isinstance(v, list) and len(v) > 0","tryCatchPattern":"try:\n    team_id, team_obj = JWTAuthManager.get_team_object(claims, ...)\nexcept Exception as e:\n    if 'No team found in token' in str(e):\n        # hint in message explains list/bracket pitfalls — surface it to the operator\n        raise ConfigError(str(e)) from e\n    raise","preventionTips":["Never use bracket or dot-index notation ('roles[0]', 'roles.0') in team_id_jwt_field; use the bare list field.","Assert the configured field exists in a decoded sample token in integration tests.","Keep a matrix of IdP -> team claim name in the deployment docs."],"tags":["litellm","jwt-auth","team-mapping","claim-mapping","azure-ad"],"backgroundTag":"jwt-team-claim-missing","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}