{"record":{"id":"c9292b61916255a4","repo":"passbolt/passbolt_api","slug":"using-callbacks-for-usercustomfilter-is-not-supported","errorCode":null,"errorMessage":"Using callbacks for userCustomFilter is not supported anymore. Please use LDAP search filter instead.","messagePattern":"Using callbacks for userCustomFilter is not supported anymore\\. Please use LDAP search filter instead\\.","errorType":"exception","errorClass":"InvalidArgumentException","httpStatus":null,"severity":"error","filePath":"plugins/PassboltEe/DirectorySync/src/Utility/LdapDirectory.php","lineNumber":552,"sourceCode":"    {\n        $directoryResults = $this->getFilteredDirectoryResults();\n\n        return $directoryResults->getGroupsAsArray();\n    }\n\n    /**\n     * Customize users query as per configuration (if available).\n     *\n     * @param \\LdapRecord\\Query\\Builder $query query\n     * @return \\LdapRecord\\Query\\Builder\n     * @throws \\InvalidArgumentException If userCustomFilter callback is used.\n     * @throws \\InvalidArgumentException If userCustomFilter cannot be parsed.\n     */\n    private function _customizeUsersQuery(Builder $query): Builder\n    {\n        $userCustomFilter = $this->directorySettings->getUserCustomFilters();\n        if (is_callable($userCustomFilter)) {\n            throw new InvalidArgumentException(\n                'Using callbacks for userCustomFilter is not supported anymore. Please use LDAP search filter instead.'\n            );\n        } elseif (is_string($userCustomFilter)) {\n            try {\n                $filter = Parser::parse($userCustomFilter);\n                $query->rawFilter(Parser::assemble($filter));\n            } catch (ParserException $pe) {\n                throw new InvalidArgumentException(\n                    'An error has occurred parsing userCustomFilter: ' . $pe->getMessage()\n                );\n            }\n        }\n\n        return $query;\n    }\n\n    /**\n     * Customize groups query as per configuration (if available).","sourceCodeStart":534,"sourceCodeEnd":570,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltEe/DirectorySync/src/Utility/LdapDirectory.php#L534-L570","documentation":"DirectorySync's LDAP user query customization no longer accepts PHP callable filters. When the stored userCustomFilter setting is a callable, _customizeUsersQuery throws this InvalidArgumentException to force migration to standard LDAP search filter strings, which are parsed and applied as raw filters on the LDAP query builder.","triggerScenarios":"Calling _fetchAndInitializeUsersQuery (user LDAP lookup) when directorySettings->getUserCustomFilters() returns a callable — i.e., the org settings or custom plugin registered a callback-based filter.","commonSituations":"Upgrading passbolt DirectorySync from an old version where callback filters were allowed; a custom integration still defining userCustomFilter as a closure in directory settings code.","solutions":["Replace the callable userCustomFilter with an equivalent LDAP search filter string, e.g. '(objectClass=user)', stored via the directory sync settings","Remove any code that sets userCustomFilter as a Closure/callable","Test the new filter string with the LDAP provider before re-enabling sync"],"exampleFix":"// before\n$settings->setUserCustomFilters(function (Builder $query) { $query->where([' Department' => 'IT']); });\n// after\n$settings->setUserCustomFilters('(department=IT)');","handlingStrategy":"validation","validationCode":"$filter = $this->directorySettings->getUserCustomFilters();\nif (is_callable($filter)) {\n    throw new RuntimeException('userCustomFilter must be an LDAP filter string, not a callback');\n}","typeGuard":"$filter = is_string($customFilter) ? $customFilter : null;","tryCatchPattern":null,"preventionTips":["Always define custom LDAP filters as filter strings, never closures","After upgrading DirectorySync, grep configuration for setUserCustomFilters callbacks","Document the filter format in your deployment config"],"tags":["ldap","directory-sync","deprecated-api","configuration"],"backgroundTag":"deprecated-api-usage","analyzedSha":"31c1bbc10f32808a607fa9bd81891e898779c0bc","analyzedAt":"2026-09-17T00:04:38.960Z","contentChangedAt":"2026-09-17T00:04:38.960Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}