Table of Contents
Problem
The OX Connector cannot synchronize a renamed LDAP group. Open-Xchange rejects the update because another group with the target name already exists in the same OX context.
Relevant error:
zeep.exceptions.Fault: Group ABCD already exists in this context
The connector log shows that the LDAP object was renamed:
Found old object cn=ABCC,... (<OBJECT_UUID>; groups/group; old:<ID>)
Group ABCC was OX Group
Group ABCD will be OX Group
The connector repeatedly retries the task. Group synchronization remains blocked.
The relevant connector log is:
/var/log/univention/listener_modules/ox-connector.log
Cause
The univentionObjectIdentifier identifies the LDAP object in the connector queue and bookkeeping database. It is not necessarily used as the group name in OX.
If OX_GROUP_IDENTIFIER is unset, the connector uses name:
GROUP_IDENTIFIER = os.environ.get("OX_GROUP_IDENTIFIER", "name")
During a group rename, the connector:
- Loads the old group name from its last successful snapshot.
- Searches OX for the group with the old name.
- Obtains the existing OX group ID.
- Changes that OX group to the new name.
- Receives an error if another group already uses the new name in the same context.
Example:
| OX ID | Name | Members | Role |
|---|---|---|---|
7001 |
ABCC |
Present | Source group that must be renamed |
145 |
ABCD |
None | Stale group blocking the target name |
The connector attempts the following operation:
Change OX group ID 7001 from ABCC to ABCD
OX rejects the operation because group ID 145 already uses the name ABCD.
A stale group can remain in OX after its LDAP object has been removed, after an incomplete synchronization, or after manual provisioning.
Investigation
Verify the LDAP Group
Confirm that only one LDAP group uses the target name:
univention-ldapsearch -LLL '(&(objectClass=univentionGroup)(cn=ABCD))' dn cn univentionObjectIdentifier
Do not remove the OX group if another active LDAP object owns the same name.
Find the OX Context
Search the connector log for the affected object UUID:
grep -C 30 '<OBJECT_UUID>' /var/log/univention/listener_modules/ox-connector.log
Search rotated logs if necessary:
zgrep -h -C 30 '<OBJECT_UUID>' /var/log/univention/listener_modules/ox-connector.log*
Find the corresponding context ID:
Processing object in context ... context=<CONTEXT_ID>
Inspect the OX Groups Through SOAP
Enter the connector container:
univention-app shell ox-connector
Query the old and new group names in the affected context:
CONTEXT_ID=253 OLD_NAME='ABCC' NEW_NAME='ABCD' python3 -c 'import os; import univention.ox.soap.backend; from univention.ox.provisioning.helpers import get_obj_by_name_from_ox; from univention.ox.soap.backend_base import get_ox_integration_class; Group=get_ox_integration_class("SOAP","Group"); context=int(os.environ["CONTEXT_ID"]); [(print(name,"not found") if group is None else print(name,"OX ID:",group.id,"Display name:",group.display_name,"Members:",list(group.members or []))) for name in (os.environ["OLD_NAME"],os.environ["NEW_NAME"]) for group in [get_obj_by_name_from_ox(Group,context,name)]]'
Confirm all of the following conditions:
- The groups have different OX IDs.
- The old group has the expected members.
- The group using the target name is empty or otherwise confirmed as stale.
- No other LDAP group owns the target name.
- The populated source group is not the group selected for removal.
Inspect the OX Database Record
Optionally inspect the conflicting group directly in the OX database:
SELECT * FROM `groups` WHERE `cid`=253 AND `id`=145\G
Display the available columns:
SHOW COLUMNS FROM `groups`;
The lastModified column contains a Unix timestamp in milliseconds. Convert it to seconds before passing it to date:
date --date='@1701102608.776'
lastModified records the most recent change. It does not necessarily record the creation time.
Solution
Remove the Confirmed Stale OX Group
Use the SOAP API from inside the connector container.
The following command loads the group by its exact OX ID. It verifies the expected name and requires an empty member list before deleting the group:
CONTEXT_ID=253 GROUP_ID=145 GROUP_NAME='ABCD' python3 -c 'import os; import univention.ox.soap.backend; from univention.ox.soap.backend_base import get_ox_integration_class; Group=get_ox_integration_class("SOAP","Group"); context=int(os.environ["CONTEXT_ID"]); group_id=int(os.environ["GROUP_ID"]); expected=os.environ["GROUP_NAME"]; group=Group.from_ox(context,obj_id=group_id); assert group.name==expected,"Unexpected group name: %r" % group.name; assert not group.members,"Group still has members: %r" % group.members; print("Removing stale OX group",group.id,group.name); group.remove()'
Never delete the populated source group. In the example, OX ID 7001 must remain.
Retry Connector Processing
Check whether the object remains in the task queue or was moved to the morgue:
univention-app shell ox-connector /usr/sbin/univention-ox-connector-task-management show-item --obj-id='<OBJECT_UUID>'
If the object remains in the task queue, restart the Listener Converter:
systemctl restart univention-appcenter-listener-converter@ox-connector.service
If the object is in the morgue, retry it and restart the Listener Converter:
univention-app shell ox-connector /usr/sbin/univention-ox-connector-task-management retry-from-morgue --obj-id='<OBJECT_UUID>'
systemctl restart univention-appcenter-listener-converter@ox-connector.service
Verify the Result
Confirm that the original populated group now uses the new name while retaining its OX ID and members:
CONTEXT_ID=253 GROUP_ID=7001 python3 -c 'import os; import univention.ox.soap.backend; from univention.ox.soap.backend_base import get_ox_integration_class; Group=get_ox_integration_class("SOAP","Group"); group=Group.from_ox(int(os.environ["CONTEXT_ID"]),obj_id=int(os.environ["GROUP_ID"])); print("OX ID:",group.id,"Name:",group.name,"Display name:",group.display_name,"Members:",list(group.members or []))'
The expected result is:
- The populated group retains its original OX ID.
- The group name changes from the old LDAP name to the new LDAP name.
- The existing member list remains intact.
- The stale conflicting OX group no longer exists.
- The connector task completes successfully.
Additional Notes
The OX Group SOAP type contains only the following relevant fields:
displayname, id, members, name
It does not provide a creation timestamp.
If the OX groups table has no creation column, the exact creation time can only be reconstructed from retained connector logs, OX audit logs, MySQL binary logs, or historical database backups.
Setting OX_GROUP_IDENTIFIER=entryUUID can prevent name collisions during future LDAP renames. Changing this setting in an existing installation requires a controlled migration and is not an immediate recovery procedure.