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
- Test the exact filter string against your directory first: ldapsearch -H <url> -D <dn> -W -b <base> '(objectclass=person)'.
- Use a syntactically complete filter with balanced parentheses, e.g. "(objectClass=person)" or "(&(objectClass=user)(memberOf=CN=dev,OU=groups,DC=example,DC=com))".
- 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
- Every filter change goes through ldapsearch first: ldapsearch -b <base> '<filter>' uid.
- Keep filters fully parenthesized per RFC 2254 and escape * ( ) \ NUL.
- Beware YAML/env quoting that can mangle parentheses in config pipelines.
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.