goharbor/harbor · error

invalid filter syntax

Error message

invalid filter syntax

What it means

Sentinel error returned by Session.SearchLdapAttribute when the LDAP filter is empty after normalization or fails goldap.CompileFilter — i.e. ldap_search_filter (or a group filter) is blank or syntactically invalid per RFC 2254. It aborts user search (POST /api/v2.0/ldap/users/search), user import, and group search.

Source

Thrown at src/pkg/ldap/ldap.go:54

var ErrNotFound = errors.New("entity not found")

// ErrEmptyPassword ...
var ErrEmptyPassword = errors.New("empty password")

// ErrInvalidCredential ...
var ErrInvalidCredential = errors.New("invalid credential")

// ErrLDAPServerTimeout ...
var ErrLDAPServerTimeout = errors.New("ldap server network timeout")

// ErrLDAPPingFail ...
var ErrLDAPPingFail = errors.New("fail to ping LDAP server")

// ErrDNSyntax ...
var ErrDNSyntax = errors.New("invalid DN syntax")

// ErrInvalidFilter ...
var ErrInvalidFilter = errors.New("invalid filter syntax")

// ErrEmptyBaseDN ...
var ErrEmptyBaseDN = errors.New("empty base dn")

// ErrEmptySearchDN ...
var ErrEmptySearchDN = errors.New("empty search dn")

// Session - define a LDAP session
type Session struct {
	basicCfg models.LdapConf
	groupCfg models.GroupConf
	ldapConn *goldap.Conn
}

// NewSession create session with configs
func NewSession(basicCfg models.LdapConf, groupCfg models.GroupConf) *Session {
	return &Session{
		basicCfg: basicCfg,

View on GitHub (pinned to 7b2fd08cc5)

Solutions

  1. Test the exact filter string against your directory first: ldapsearch -H <url> -D <dn> -W -b <base> '(objectclass=person)'.
  2. Use a syntactically complete filter with balanced parentheses, e.g. "(objectClass=person)" or "(&(objectClass=user)(memberOf=CN=dev,OU=groups,DC=example,DC=com))".
  3. Save via PUT /api/v2.0/configurations (ldap_search_filter) and re-run POST /api/v2.0/ldap/users/search to confirm.

Example fix

# before (unbalanced parens)
curl -X PUT https://harbor/api/v2.0/configurations -d '{"ldap_search_filter": "(objectclass=person"}'
# after
curl -X PUT https://harbor/api/v2.0/configurations -d '{"ldap_search_filter": "(objectclass=person)"}'
Defensive patterns

Strategy: validation

Validate before calling

// Go: apply Harbor's own checks to a filter before configuring/using it
filter = strings.TrimSpace(filter)
if filter == "" { fail("empty ldap_search_filter") }
if _, err := goldap.CompileFilter(filter); err != nil {
    fail("filter does not compile: " + err.Error())
}

Type guard

func isLdapInvalidFilter(err error) bool { return errors.Is(err, ldap.ErrInvalidFilter) }

Try / catch

if errors.Is(err, ldap.ErrInvalidFilter) {
    // re-validate ldap_search_filter / group filter with ldapsearch or CompileFilter,
    // fix parentheses/escaping, save via PUT configurations, then retry the search
}

Prevention

When it happens

Trigger: ldap_search_filter left empty and the built filter still normalizes to ""; a filter with unbalanced parentheses such as "(objectclass=person" ; a bare assertion "objectclass=person" that the normalizer/compiler rejects; stray quotes or LDAP-special characters ( ) * \ unescaped in the config value.

Common situations: Copying filters from AD documentation that use a different dialect; env-var quoting that strips parens in docker-compose/Kubernetes; leaving the filter empty assuming a default (some directories need at least (objectClass=*)) — note Harbor's normalizeFilter wraps bare assertions but empty-after-normalize is still fatal.

Related errors


AI-assisted analysis of goharbor/harbor@7b2fd08cc5 (2026-08-16). Data as JSON: /api/errors/9331a24c2b38e7a4. Report an issue: GitHub.