Community Note
- Please vote on this issue by adding a π reaction to the original issue to help the community and maintainers prioritize this request.
- Please do not leave +1 or me too comments, they generate extra noise for issue followers and do not help prioritize the request.
- If you are interested in working on this issue or have submitted a pull request, please leave a comment.
Before submitting a bug report, we ask that you first search existing issues and pull requests to see if someone else may have experienced the same issue or may have already submitted a fix for it.
Python Version & Okta SDK Version(s)
Python v3.11.9
okta 3.4.3
Affected Class/Method(s)
okta.models.group_profile
okta.UserClient.list_user_groups
Customer Information
Organization Name: Hudson River Trading
Paid Customer: yes
Code Snippet
import okta.client
import okta.exceptions
okta_client = okta.client.Client(
{
"orgUrl": org_url,
"authorizationMode": "PrivateKey",
"clientId": client_id,
"privateKey": private_key,
"scopes": ["okta.users.read", "okta.groups.read"],
"kid": "<kid>",
}
)
try:
# Get user status and ID
okta_user, _, err = await okta_client.get_user(user)
if err or not okta_user:
error_message = (
f"User '{user}' not found in Okta or error fetching user: {err}"
)
print(f"WARNING: {error_message}")
return None, error_message
user_data["status"] = okta_user.status
user_data["id"] = okta_user.id
# Get user groups
all_groups = []
okta_user_groups, resp, err = await okta_client.list_user_groups(okta_user.id)
if okta_user_groups:
all_groups.extend(okta_user_groups)
while resp and resp.has_next():
next_groups, next_err = await resp.next()
if next_err:
error_message = f"Error for paginated groups for '{user}': {next_err}"
print(f"WARNING: {error_message}")
break
if next_groups:
all_groups.extend(next_groups)
if not error_message:
user_data["groups"] = all_groups
else:
user_data["groups"] = []
except okta.exceptions.OktaAPIException as okta_api_error:
error_message = (
f"Error occurred while looking up user '{user}' in Okta." # type: ignore[attr-defined]
f"\nError Code: {okta_api_error.code}"
f" Error Message: {okta_api_error.message}"
)
print(f"WARNING: {error_message}")
return None, error_message
except Exception as error:
error_message = (
f"An unexpected error occurred while looking up user '{user}' in Okta."
f"\nError Message: {error}"
)
print(f"WARNING: {error_message}", style="warning")
return None, error_message
Debug Output / Traceback
'ApiResponse' object has no attribute 'has_next'
Expected Behavior
User groups returned
Actual Behavior
Errors
Summary
Between okta==2.9.x and okta==3.4.3 the SDK models were regenerated from the
OpenAPI 5.1.0 spec with pydantic v2. GroupProfile changed from a single
permissive object into a strict anyOf union of OktaUserGroupProfile and
OktaActiveDirectoryGroupProfile. This introduced two regressions that break
Client.list_user_groups() (and any Group-returning endpoint) for group data
that 2.9.x handled without error.
okta 2.9.x β okta/models/group_profile.py
GroupProfile(OktaObject) is a single flat object. Fields live directly on it
(group.profile.name, group.profile.description), custom/AD attributes are set
as plain attributes, and unknown fields are silently retained. It never raises.
okta 3.4.3 β okta/models/group_profile.py
GroupProfile(BaseModel) is an anyOf of two strict pydantic models:
| Model |
Allowed objectClass |
Fields |
OktaUserGroupProfile |
okta:user_group |
description, name, objectClass (all StrictStr) |
OktaActiveDirectoryGroupProfile |
okta:windows_security_principal |
AD-specific fields (all StrictStr) |
The profile fields are no longer on GroupProfile itself β they live on
group.profile.actual_instance.
Issue 1 β attribute access breaks (silent API break)
group.profile.name
# AttributeError: 'GroupProfile' object has no attribute 'name'
Callers must now use group.profile.actual_instance.name.
Issue 2 β deserialization crashes (hard break)
GroupProfile.from_json tries each strict member and, if neither matches, raises:
ValueError: No match found when deserializing the JSON string into GroupProfile
with anyOf schemas: OktaActiveDirectoryGroupProfile, OktaUserGroupProfile.
Reproduced for real-world group profiles that 2.9.x accepted:
| Profile |
2.9.x |
3.4.3 |
objectClass: okta:user_group |
OK |
OK |
objectClass: okta:windows_security_principal |
OK |
OK |
objectClass: okta:app_group (or any other/future value) |
OK |
CRASH |
custom attribute with non-string value (e.g. int) |
OK |
CRASH (StrictStr) |
Because this happens inside SDK deserialization, the caller can't avoid it; if a
user belongs to even one such group, list_user_groups() fails entirely.
Issue 3 β pagination crash (okta/api_response.py)
OktaAPIResponse.next() builds models positionally for
User/Group/UserSchema/GroupSchema:
self._type(item) # item is a dict
pydantic v2 BaseModel.__init__ rejects a positional dict, so the 2nd and
later pages of any paginated call raise:
TypeError: BaseModel.__init__() takes 1 positional argument but 2 were given
Steps to reproduce
- Install okta==2.9.X package
- Run test code to successfully get user groups
- Install okta==3.4.3 (ie latest)
- Run test code and note failures
References
No response
Community Note
Before submitting a bug report, we ask that you first search existing issues and pull requests to see if someone else may have experienced the same issue or may have already submitted a fix for it.
Python Version & Okta SDK Version(s)
Python v3.11.9
okta 3.4.3
Affected Class/Method(s)
okta.models.group_profile
okta.UserClient.list_user_groups
Customer Information
Organization Name: Hudson River Trading
Paid Customer: yes
Code Snippet
Debug Output / Traceback
Expected Behavior
User groups returned
Actual Behavior
Errors
Summary
Between
okta==2.9.xandokta==3.4.3the SDK models were regenerated from theOpenAPI 5.1.0 spec with pydantic v2.
GroupProfilechanged from a singlepermissive object into a strict
anyOfunion ofOktaUserGroupProfileandOktaActiveDirectoryGroupProfile. This introduced two regressions that breakClient.list_user_groups()(and any Group-returning endpoint) for group datathat
2.9.xhandled without error.okta 2.9.x β
okta/models/group_profile.pyGroupProfile(OktaObject)is a single flat object. Fields live directly on it(
group.profile.name,group.profile.description), custom/AD attributes are setas plain attributes, and unknown fields are silently retained. It never raises.
okta 3.4.3 β
okta/models/group_profile.pyGroupProfile(BaseModel)is ananyOfof two strict pydantic models:objectClassOktaUserGroupProfileokta:user_groupdescription,name,objectClass(allStrictStr)OktaActiveDirectoryGroupProfileokta:windows_security_principalStrictStr)The profile fields are no longer on
GroupProfileitself β they live ongroup.profile.actual_instance.Issue 1 β attribute access breaks (silent API break)
Callers must now use
group.profile.actual_instance.name.Issue 2 β deserialization crashes (hard break)
GroupProfile.from_jsontries each strict member and, if neither matches, raises:Reproduced for real-world group profiles that 2.9.x accepted:
objectClass: okta:user_groupobjectClass: okta:windows_security_principalobjectClass: okta:app_group(or any other/future value)int)StrictStr)Because this happens inside SDK deserialization, the caller can't avoid it; if a
user belongs to even one such group,
list_user_groups()fails entirely.Issue 3 β pagination crash (
okta/api_response.py)OktaAPIResponse.next()builds models positionally forUser/Group/UserSchema/GroupSchema:pydantic v2
BaseModel.__init__rejects a positional dict, so the 2nd andlater pages of any paginated call raise:
Steps to reproduce
References
No response