symfony/symfony · error · InvalidConfigurationException
Using "ldap_users_only" on the "%s" firewall requires a user
Error message
Using "ldap_users_only" on the "%s" firewall requires a user provider that returns "%s" instances, but none of the providers it uses does.
What it means
Thrown when you enable the "ldap_users_only" option on an LDAP-authenticating firewall (e.g. form_login_ldap) but the configured user provider(s) do not return Symfony\Component\Ldap\Security\LdapUser instances. The flag tells CheckLdapCredentialsListener to authenticate only users sourced directly from LDAP, so at container-compile time the bundle calls providesLdapUsers() which recursively inspects the provider (and ChainUserProvider legs) for an LdapUserProvider.
Source
Thrown at src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/LdapFactoryTrait.php:65
// well, so move the decorated one aside and hand the id back, to let both variants be
// configured on the same firewall
$decoratedId = 'security.authenticator.'.$key.'.'.$firewallName.'.inner';
$container->setDefinition($decoratedId, $container->getDefinition($authenticatorId));
$container->removeDefinition($authenticatorId);
if (isset($definitions[$authenticatorId])) {
$container->setDefinition($authenticatorId, $definitions[$authenticatorId]);
}
$authenticatorId = $decoratedId;
if ($config['ldap_users_only']) {
if (!property_exists(CheckLdapCredentialsListener::class, 'ldapUsersOnly')) {
throw new InvalidConfigurationException('Using "ldap_users_only" requires symfony/ldap 8.2 or higher, the installed version would ignore it.');
}
if (false === self::providesLdapUsers($container, $userProviderId)) {
throw new InvalidConfigurationException(\sprintf('Using "ldap_users_only" on the "%s" firewall requires a user provider that returns "%s" instances, but none of the providers it uses does.', $firewallName, LdapUser::class));
}
}
$container->setDefinition('security.listener.'.$key.'.'.$firewallName, new Definition(CheckLdapCredentialsListener::class))
->addTag('kernel.event_subscriber', ['dispatcher' => 'security.event_dispatcher.'.$firewallName])
->addArgument(new Reference('security.ldap_locator'))
->addArgument($config['ldap_users_only'])
;
$ldapAuthenticatorId = 'security.authenticator.'.$key.'.'.$firewallName;
$definition = $container->setDefinition($ldapAuthenticatorId, new Definition(LdapAuthenticator::class))
->setArguments([
new Reference($authenticatorId),
$config['service'],
$config['dn_string'],
$config['search_dn'],
$config['search_password'],
]);View on GitHub (pinned to 698e28026c)
Solutions
- Set the firewall's provider key to an LDAP user provider configured under security.providers with type ldap.
- If using a chain provider, ensure at least one leg is an LdapUserProvider.
- If you also need to authenticate non-LDAP users, remove ldap_users_only: true.
Example fix
# before
security:
firewalls:
main:
provider: users_in_memory
form_login_ldap:
service: Symfony\Component\Ldap\Ldap
dn_string: 'ou=users,dc=example,dc=com'
ldap_users_only: true
# after
security:
providers:
my_ldap:
ldap:
service: Symfony\Component\Ldap\Ldap
base_dn: 'ou=users,dc=example,dc=com'
search_dn: 'cn=admin,dc=example,dc=com'
search_password: secret
firewalls:
main:
provider: my_ldap
form_login_ldap:
service: Symfony\Component\Ldap\Ldap
dn_string: 'ou=users,dc=example,dc=com'
ldap_users_only: true Defensive patterns
Strategy: validation
Validate before calling
// Before enabling ldap_users_only, verify the provider chain yields LdapUser
use Symfony\Component\Ldap\Security\LdapUserProvider;
$providerId = $firewall['provider'] ?? null;
$def = $container->findDefinition($providerId);
$class = $def?->getClass();
if ($class && !is_a($class, LdapUserProvider::class, true)) {
throw new \LogicException("ldap_users_only requires a LdapUserProvider; {$class} won't work.");
} Type guard
function isLdapUserProvider(string $class): bool
{
return is_a($class, \Symfony\Component\Ldap\Security\LdapUserProvider::class, true);
} Prevention
- Always pair ldap_users_only with an ldap-type provider under security.providers.
- When using a chain provider, confirm at least one leg is LdapUserProvider.
- Run the container compile in CI (php bin/console lint:container) to catch this before deploy.
When it happens
Trigger: Configuring a firewall with an authenticator whose key ends in "-ldap" (form_login_ldap, json_login_ldap, http_basic_ldap) and setting ldap_users_only: true, while the firewall/provider resolves to a non-LDAP provider (memory, entity, or a custom class not extending LdapUserProvider).
Common situations: Copying LDAP example config but leaving the default memory/entity provider in place; using a ChainUserProvider where none of the legs is an LdapUserProvider; enabling ldap_users_only after an upgrade without switching the provider to type ldap.
Related errors
- Using the "query_string" config without using a "search_dn"
- Using the "query_string" config without using a "search_dn"
- Using "ldap_users_only" requires symfony/ldap 8.2 or higher,
- Invalid firewall "%s": user provider "%s" not found.
- Not configuring explicitly the provider for the "%s" authent
AI-assisted analysis of symfony/symfony@698e28026c (2026-08-06).
Data as JSON: /api/errors/3dce5ba93091fa9a.
Report an issue: GitHub.