risingwavelabs/risingwave · error · PsqlError

LDAP search failed

Error message

LDAP search failed

What it means

After binding as the search user, search_and_bind runs an LDAP subtree search for the user's entry using the configured base_dn and search_filter. Any error from the search operation (network drop, malformed filter, insufficient search permissions, base_dn not found) is wrapped as this StartupError. It is a directory-query failure, not an authentication failure.

Solutions

  1. Test the search manually: ldapsearch -H ... -D bind_dn -w pass -b base_dn '(uid=testuser)' dn
  2. Escape special characters in interpolated usernames (RFC 4515 filter escaping)
  3. Verify base_dn exists and matches the directory naming context
  4. Grant the bind account read/search permissions on the user OU

Example fix

// before (unescaped interpolation breaks filter)
search_filter = '(uid={username})'
// after (escaped via library interpolation; correct attribute for AD)
search_filter = '(sAMAccountName={username})'
Defensive patterns

Strategy: try-catch

Validate before calling

// verify the search works manually before configuring
# ldapsearch -H ldaps://ldap.corp:636 -D "$BIND_DN" -w "$BIND_PASS" \
#   -b 'ou=users,dc=corp,dc=com' '(sAMAccountName=testuser)' dn

Try / catch

catch PsqlError::StartupError 'LDAP search failed'; differentiate filter-syntax errors (fix escaping) from ACL/base_dn errors (fix directory config) using the inner error text

Prevention

When it happens

Trigger: ldap.search(base_dn, Scope::Subtree, &search_filter, vec!["dn"]) awaits or resolves with Err — bad filter syntax, wrong base_dn, search privileges missing for the bind account

Common situations: Search filter template with unescaped special characters in username ((uid=j.o'brien) breaks filter syntax); base_dn typo'd or points at a non-existent subtree; bind account lacks read/search ACLs on the user subtree; AD requires the filter to use sAMAccountName instead of uid.

Understand the failure class

Background: Database query failed: Internal Server Error 500s wrapping SQL, Prisma, and connection failures — what to check first — this error's family across 16 libraries.

Related errors


AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11). Data as JSON: /api/errors/d07189feb8d2c387. Report an issue: GitHub.

Appendix: source

Thrown at src/utils/pgwire/src/ldap_auth.rs:516

        // Build search filter
        let search_filter = if let Some(filter_template) = &self.config.search_filter {
            // Use custom filter template with $username placeholder
            // SECURITY: Escape username to prevent LDAP filter injection
            let escaped_username = ldap_escape(username);
            filter_template.replace("$username", &escaped_username)
        } else {
            // Default filter using search_attribute (defaults to "uid" if not configured)
            // SECURITY: Escape username to prevent LDAP filter injection
            let escaped_username = ldap_escape(username);
            let attr = self.config.search_attribute.as_deref().unwrap_or("uid");
            format!("({}={})", attr, escaped_username)
        };

        let rs = ldap
            .search(base_dn, Scope::Subtree, &search_filter, vec!["dn"])
            .await
            .map_err(|e| {
                PsqlError::StartupError(anyhow!(e).context("LDAP search failed").into())
            })?;

        // If no user found, authentication fails
        let search_entries: Vec<SearchEntry> =
            rs.0.into_iter().map(SearchEntry::construct).collect();
        if search_entries.is_empty() {
            return Ok(false);
        }

        // Attempt to bind with the user's DN and password
        let user_dn = &search_entries[0].dn;

        let bind_result = ldap
            .simple_bind(user_dn, password)
            .await
            .map_err(|e| PsqlError::StartupError(anyhow!(e).context("LDAP bind failed").into()));

        // Explicitly unbind the connection

View on GitHub (pinned to 6469eb736d)