passbolt/passbolt_api · error · BadRequestException

The directory structure cannot be retrieved.

Error message

The directory structure cannot be retrieved.

What it means

Thrown by the DirectorySettingsController::test() endpoint when converting the LDAP directory tree (getTree()) to an array for the API response fails. This endpoint runs a dry-run of the LDAP configuration against the live directory and returns users, groups and their hierarchy; a failure here means the tree data returned by the LDAP connection was inconsistent or an exception occurred while serializing it.

Solutions

  1. Read the appended $e->getMessage() in the response body to identify the underlying serialization/tree error
  2. Check the LDAP directory for broken group memberships or orphaned entries (groups whose parent DN does not exist)
  3. Re-run the test endpoint after fixing LDAP data; compare with a fresh ldapsearch output
  4. If triggered by specific users/groups, exclude them via filters in the LDAP settings and re-test

Example fix

// before: broken tree from cyclic group membership
groupOfNames -> memberOf -> groupOfNames (cycle)
// after: remove the cycle or filter the offending group in the LDAP filter settings
'groupFilter' => '(&(objectClass=groupOfNames)(!(memberOf=<bad-parent-dn>)))'
Defensive patterns

Strategy: try-catch

Validate before calling

// client-side pre-check before calling the test endpoint
if (!settings.ldap.host || !settings.ldap.port) throw new Error('LDAP host/port required');

Type guard

$tree = $filteredDirectoryResults->getTree();
if (!is_array($tree)) {
    throw new BadRequestException('Directory tree is not a traversable structure.');
}

Try / catch

try {
    $res = await api.post('/directorysync/settings/test', settings);
} catch (e) {
    if (e.message.includes('directory structure cannot be retrieved')) {
        logLdapTreeIssue(e.message); // underlying cause appended after the message
    }
}

Prevention

When it happens

Trigger: POST /directorysync/settings/test with valid LDAP settings where the resulting FilteredDirectoryResults object's getTree() throws during _toArray() — e.g. malformed group memberships, entries referencing missing parents, or LDAP attributes in unexpected formats.

Common situations: LDAP servers with cyclic or broken group parent relationships; partially migrated AD/LDAP trees; entries deleted between the fetch of users/groups and the tree build; custom LDAP schemas producing unexpected attribute types.

Related errors


AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17). Data as JSON: /api/errors/9caec05b5d9d7b54. Report an issue: GitHub.

Appendix: source

Thrown at plugins/PassboltEe/DirectorySync/src/Controller/DirectorySettingsController.php:146

        try {
            $settings = LdapConfigurationForm::formatFormDataToOrgSettings($data);
            $orgSettings = new DirectoryOrgSettings($settings);
            $directory = DirectoryFactory::get($orgSettings);
            $filteredDirectoryResults = $directory->getFilteredDirectoryResults();
            $outputData = [
                'users' => $this->_toArray(array_values($filteredDirectoryResults->getUsers())),
                'groups' => $this->_toArray(array_values($filteredDirectoryResults->getGroups())),
            ];
        } catch (Exception $e) {
            throw new BadRequestException('The users and groups cannot be retrieved. ' . $e->getMessage());
        }

        try {
            $outputData['tree'] = $this->_toArray($filteredDirectoryResults->getTree());
        } catch (Exception $e) {
            $msg = __('The directory structure cannot be retrieved.');
            throw new BadRequestException($msg . ' ' . $e->getMessage());
        }

        try {
            $invalidObjects = $filteredDirectoryResults->getInvalidGroups();
            $invalidObjects = array_merge($invalidObjects, $filteredDirectoryResults->getInvalidUsers());
            $outputData['errors'] = $this->_toArray($invalidObjects);
        } catch (Exception $e) {
            $msg = __('There was an issue while retrieving the invalid entries.');
            throw new BadRequestException($msg . ' ' . $e->getMessage());
        }

        $this->success(__('The operation was successful.'), $outputData);
    }

    /**
     * Disable the ldap integration.
     *
     * @return void

View on GitHub (pinned to 31c1bbc10f)