Problem: OX-Connector Stops Processing New Provisioning Tasks Due to Invalid Listener Spool File (`entry_uuid = null`)

OX Connector Stops Processing New Provisioning Tasks Due to Invalid Listener Spool File (entry_uuid = null)

Problem

On the customer’s OX server, the OX Connector intermittently failed to provision newly enabled user accounts and mailboxes.

After enabling a UCS user for OX, the listener correctly detected the change and logged the provisioning event:

2026-06-23T15:02:22.202486+02:00  PROCESS ox-connector: create of uid=<redacted>,cn=users,dc=<redacted>,dc=<redacted> (id: b'<redacted>', file: /var/lib/univention-appcenter/listener/ox-connector/2026-06-23-15-02-22-200253.json)

The corresponding JSON file was successfully created in the listener spool directory and contained valid data. However, it was never processed by the connector.

Running a connector resynchronization

univention-directory-listener-ctrl resync ox-connector

sometimes resulted in additional objects being synchronized, but the provisioning process remained unreliable and the issue was not completely resolved.

/var/log/univention/listener_modules/ox-connector.log

2026-06-24 00:00:04 INFO    Started up with ox-connector=3.1.0
2026-06-24 00:00:04 INFO    Using App account connection
2026-06-24 00:00:04 ERROR   Fatal error:
Traceback (most recent call last):
  File "/usr/share/univention-appcenter-listener-converter", line 186, in main
    find_and_convert_files(app)
  File "/usr/share/univention-appcenter-listener-converter", line 162, in find_and_convert_files
    if convert(app, dumped, filename, lo, pos):
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/share/univention-appcenter-listener-converter", line 94, in convert
    objs = search_objects(udm_type, lo, pos, univentionObjectIdentifier=entry_uuid)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/univention/appcenter/udm.py", line 96, in search_objects
    expressions.append(udm_filter.expression(key, escape_filter_chars(value), '='))
                                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/ldap/filter.py", line 28, in escape_filter_chars
    raise TypeError("assertion_value must be of type str.")
TypeError: assertion_value must be of type str.

Environment

  • UCS: 5.2-6 errata492

  • Installed:

    • fetchmail=6.4.37
    • mailserver=16.0
    • ox-connector=3.1.0
    • prometheus-node-exporter=2.0.1
    • ucsschool=5.2 v1

Root Cause

The exception

TypeError: assertion_value must be of type str.

indicates that a Python function expected a string (str) but instead received None (or another invalid data type).

The traceback clearly shows the execution flow.

The script

/usr/share/univention-appcenter-listener-converter

scans the App Center listener spool directory for cached synchronization files created by the OX Connector (find_and_convert_files).

It loads one of these files and attempts to read the unique LDAP object identifier (univentionObjectIdentifier), internally stored as entry_uuid.

In this particular file, however, the UUID was missing entirely (null).

When the converter attempted to build an LDAP filter using this value (escape_filter_chars(value)), the script terminated because Python 3 strictly requires a string value.

The affected file was identified using:

grep -E '"entry_uuid"\s*:\s*null' /var/lib/univention-appcenter/listener/ox-connector/*

Output:

/var/lib/univention-appcenter/listener/ox-connector/2026-06-23-14-52-10-579912.json:    "entry_uuid": null,

Inspecting the JSON file confirmed the invalid entry:

python3 -m json.tool /var/lib/univention-appcenter/listener/ox-connector/2026-06-23-14-52-10-579912.json
{
    "command": "modify",
    "dn": "cn=<redacted>,cn=klassen,cn=<redacted>,cn=groups,ou=<redacted>,dc=<redacted>,dc=<redacted>",
    "entry_uuid": null,
    "object_type": "groups/group"
}

The missing entry_uuid caused the listener converter to terminate before processing any subsequent synchronization tasks.


Investigation

The directory

/var/lib/univention-appcenter/listener/ox-connector/

contains the JSON files processed by the script

/usr/share/univention-appcenter-listener-converter

The converter scans this App Center spool directory for cached synchronization files created by the OX Connector (find_and_convert_files). It reads each JSON file and attempts to retrieve the unique LDAP object identifier (univentionObjectIdentifier), internally referred to as entry_uuid.

Directory contents:

root@ox:~/univention-support # ls -lah /var/lib/univention-appcenter/listener/ox-connector/
total 268K
drwxr-xr-x 2 root nogroup 264K Jun 24 16:21 .
drwxr-xr-x 3 root nogroup 4.0K Jun 23 14:51 ..

The connector task database is located in:

root@ox:~/univention-support # ls -lah /var/lib/univention-appcenter/apps/ox-connector/data/listener/
total 235M
drwxr-xr-x 3 root root 496K Jun 24 16:27 .
drwxr-xr-x 5 root root 4.0K Apr 13 08:35 ..
-rw-r--r-- 1 root root 16K Apr 13 08:32 meta.db
drwxr-xr-x 2 root root 528K Apr 13 08:34 old
-rw-r--r-- 1 root root 2.1M Apr 10 09:53 old.db
-rw-r----- 1 root root 232M Jun 24 16:27 ox-connector.db
-rw-r--r-- 1 root root 0 Jun 24 10:22 univention-ox-connector-task-management.log

Pending Connector Tasks

The number of queued tasks can be determined using:

root@ox:~ # univention-ox-connector-task-management search-tasks | grep -c cn=

Output:

3168

A detailed task listing can be obtained with:

root@ox:~ # univention-ox-connector-task-management search-tasks

Example output:

DN: cn=<redacted>,cn=builtin,dc=<redacted>,dc=<redacted>
Object Identifier: <redacted>
UDM module: groups/group
ID (database): 2
Created at: 2026-06-23 12:51:57.451787
Status: new
Error count: 0
-
DN: cn=<redacted>,cn=builtin,dc=<redacted>,dc=<redacted>
Object Identifier: <redacted>
UDM module: groups/group
ID (database): 3
Created at: 2026-06-23 12:51:57.457182
Status: new
Error count: 0
-
DN: cn=<redacted>,cn=builtin,dc=<redacted>,dc=<redacted>
Object Identifier: <redacted>
UDM module: groups/group
ID (database): 6
Created at: 2026-06-23 12:51:57.473359
Status: new
Error count: 0

<remaining output omitted for brevity>

Searching for Missing Object Identifiers

The following command identifies JSON files that do not explicitly contain the attribute name univentionObjectIdentifier:

root@ox:~/univention-support # grep -Lr "univentionObjectIdentifier" /var/lib/univention-appcenter/listener/ox-connector/

Output:

/var/lib/univention-appcenter/listener/ox-connector/2026-06-24-14-41-23-368181.json
/var/lib/univention-appcenter/listener/ox-connector/2026-06-24-14-47-43-680394.json
/var/lib/univention-appcenter/listener/ox-connector/2026-06-24-14-41-23-450785.json
/var/lib/univention-appcenter/listener/ox-connector/2026-06-24-14-47-53-808937.json
/var/lib/univention-appcenter/listener/ox-connector/2026-06-24-14-41-23-742730.json
/var/lib/univention-appcenter/listener/ox-connector/2026-06-24-14-41-23-153785.json
/var/lib/univention-appcenter/listener/ox-connector/2026-06-23-14-52-10-581623.json
/var/lib/univention-appcenter/listener/ox-connector/2026-06-24-14-41-23-664960.json
/var/lib/univention-appcenter/listener/ox-connector/2026-06-24-14-41-24-254144.json
/var/lib/univention-appcenter/listener/ox-connector/2026-06-23-16-03-21-199111.json
/var/lib/univention-appcenter/listener/ox-connector/2026-06-24-14-41-23-408934.json
/var/lib/univention-appcenter/listener/ox-connector/2026-06-23-15-04-51-413551.json
/var/lib/univention-appcenter/listener/ox-connector/2026-06-24-13-58-41-187700.json
/var/lib/univention-appcenter/listener/ox-connector/2026-06-24-14-55-18-510303.json
/var/lib/univention-appcenter/listener/ox-connector/2026-06-24-14-41-23-584901.json
/var/lib/univention-appcenter/listener/ox-connector/2026-06-24-14-41-24-287092.json
/var/lib/univention-appcenter/listener/ox-connector/2026-06-24-14-55-18-471725.json
/var/lib/univention-appcenter/listener/ox-connector/2026-06-24-14-41-23-257511.json
/var/lib/univention-appcenter/listener/ox-connector/2026-06-24-14-41-23-091787.json
/var/lib/univention-appcenter/listener/ox-connector/2026-06-23-14-52-10-579912.json
/var/lib/univention-appcenter/listener/ox-connector/2026-06-24-14-41-23-541149.json
/var/lib/univention-appcenter/listener/ox-connector/2026-06-23-15-02-22-245348.json
/var/lib/univention-appcenter/listener/ox-connector/2026-06-24-14-41-23-205644.json
/var/lib/univention-appcenter/listener/ox-connector/2026-06-24-14-41-23-625495.json
/var/lib/univention-appcenter/listener/ox-connector/2026-06-24-14-41-23-704560.json

Although these files do not contain the literal attribute name univentionObjectIdentifier, they still include the corresponding value stored as entry_uuid.

Example:

root@ox:~/univention-support # python3 -m json.tool /var/lib/univention-appcenter/listener/ox-connector/2026-06-24-14-41-23-368181.json
{
    "command": "modify",
    "dn": "uid=<redacted>,cn=users,ou=<redacted>,dc=<redacted>,dc=<redacted>",
    "entry_uuid": "<redacted>",
    "object_type": "users/user"
}
root@ox:~/univention-support # python3 -m json.tool /var/lib/univention-appcenter/listener/ox-connector/2026-06-24-14-47-43-680394.json
{
    "command": "modify",
    "dn": "uid=<redacted>,cn=users,ou=<redacted>,dc=<redacted>,dc=<redacted>",
    "entry_uuid": "<redacted>",
    "object_type": "users/user"
}
root@ox:~/univention-support # python3 -m json.tool /var/lib/univention-appcenter/listener/ox-connector/2026-06-24-14-41-23-091787.json
{
    "command": "modify",
    "dn": "uid=<redacted>,cn=users,ou=<redacted>,dc=<redacted>,dc=<redacted>",
    "entry_uuid": "<redacted>",
    "object_type": "users/user"
}

These examples demonstrate that the JSON format itself is valid. The issue is limited to the malformed spool file where entry_uuid is null.

OX Connector Configuration

The current OX Connector configuration:

root@ox:~ # univention-app configure ox-connector --list
OX_SOAP_SERVER: 'https://ucs5backup.deadpool.intranet' (The server where Open-Xchange is installed)
OX_IMAP_SERVER: 'imap://ucs5backup.deadpool.intranet:143' (Default IMAP server for new users (if not set explicitely there))
OX_SMTP_SERVER: 'smtp://ucs5backup.deadpool.intranet:587' (Default SMTP server for new users (if not set explicitely there))
DEFAULT_CONTEXT: 10 (Default context for users (has to exist))
OX_LANGUAGE: 'de_DE' (Default language for new users)
LOCAL_TIMEZONE: 'Europe/Berlin' (Default timezone for new users)
OX_MASTER_ADMIN: 'oxadminmaster' (OX Admin username (the OX Admin can create, modify, delete contexts; has to exist))
OX_MASTER_PASSWORD: ',qYhiTvHg71jOzB73,3H' (OX Admin password)
Falling back to initial value for OX_IMAP_LOGIN
OX_IMAP_LOGIN: None (imapLogin field that is used by OX to log in to the user's inbox. If this value is empty it is set to the user's mail address.)
Falling back to initial value for OX_FUNCTIONAL_ACCOUNT_LOGIN_TEMPLATE
OX_FUNCTIONAL_ACCOUNT_LOGIN_TEMPLATE: None (Customizes the functional account login field format using templates. You can use plain text or incorporate UDM properties, which have to be enclosed within double curly braces, such as '{{fa_entry_uuid}}{{username}}'." For more details, please refer to the <a target="_blank" href="https://docs.software-univention.de/ox-connector-app/latest/configuration.html#envvar-OX_FUNCTIONAL_ACCOUNT_LOGIN_TEMPLATE">OX-Connector manual</a>.)
Falling back to initial value for OX_USER_IDENTIFIER
OX_USER_IDENTIFIER: None (UDM user property that is used as the unique user identifier for OX. Default: "username".)
Falling back to initial value for OX_GROUP_IDENTIFIER
OX_GROUP_IDENTIFIER: None (UDM group property that is used as the unique group identifier for OX. Default: "name".)
OX_ENABLE_DEPUTY_PERMISSIONS: False (Enables the provisioning of user deputy permissions. Additional steps are needed to activate this feature. Please refer to the instructions in the <a target="_blank")
OX_CONNECTOR_LOG_LEVEL: 'INFO' (Ox-connector log level)
OX_CONNECTOR_STOP_ON_ERROR: True (If the Connector finds an error while processing a particular object (e.g., invalid data that OX rejects), it stops. If this setting is unchecked, the App continues to process other pending tasks; the problematic object is moved to a list of errors for the Administrator to monitor at another time.)

Solution

After identifying the malformed JSON file as the root cause, the affected spool file should either be removed or moved out of the listener spool directory so that it no longer blocks task processing.

In this case, the problematic file was:

/var/lib/univention-appcenter/listener/ox-connector/2026-06-23-14-52-10-579912.json

Move the file to another location for further analysis:

mv /var/lib/univention-appcenter/listener/ox-connector/2026-06-23-14-52-10-579912.json /root/univention-support

Verify that the file has been moved successfully:

root@ox:~/univention-support # ls -lah

Output:

total 12K
drwxr-xr-x  2 root root    4.0K Jun 24 16:16 .
drwx------ 17 root root    4.0K Jun 24 16:19 ..
-rw-r--r--  1 root nogroup  212 Jun 23 14:52 2026-06-23-14-52-10-579912.json

After removing the blocking spool file, restart the listener converter service:

systemctl restart univention-appcenter-listener-converter@ox-connector.service

Once the service has restarted, the converter resumes processing the remaining queued tasks and newly generated listener events are processed again.


Additional Information

The OX Connector was configured with the following setting:

OX_CONNECTOR_STOP_ON_ERROR: True

This setting controls the connector’s behavior when processing errors occur.

With OX_CONNECTOR_STOP_ON_ERROR=True, the connector immediately stops processing as soon as it encounters an invalid task or malformed listener JSON file. While this behavior prevents potentially inconsistent provisioning, it also causes the complete synchronization queue to become blocked. As a result, all subsequent provisioning operations remain pending until the blocking task has been removed.

If the preferred behavior is to continue processing subsequent tasks while skipping only the faulty one, the configuration can be changed as follows:

univention-app configure ox-connector --set OX_CONNECTOR_STOP_ON_ERROR=False

With this configuration:

  • Invalid tasks are skipped instead of blocking the queue.
  • Failed tasks are added to the connector’s error list for later investigation.
  • Subsequent synchronization operations continue to be processed.
  • A single malformed listener JSON file no longer prevents the provisioning of additional users or groups.

This configuration may be preferable in larger environments where continuous provisioning is more important than stopping the queue on the first processing error.


Conclusion

The provisioning issue was not caused by the OX Connector itself, but by a malformed listener spool file containing an invalid entry_uuid (null).

Because the connector was configured with OX_CONNECTOR_STOP_ON_ERROR=True, processing stopped at the first invalid task and all subsequent synchronization operations remained queued.

Removing the malformed listener file and restarting the listener converter immediately restored normal processing.

To avoid future queue blocking caused by individual malformed tasks, consider configuring the connector with:

OX_CONNECTOR_STOP_ON_ERROR=False

This allows the connector to continue processing subsequent synchronization tasks while recording faulty objects for later investigation.