pentaho/pentaho-kettle · error · KettleException
LDAPConnection.Error.Search
LDAPConnection.Error.Search
Error message
LDAPConnection.Error.Search
What it means
LDAPConnection.search() wraps any exception from the JNDI InitialContext.search() call (LDAP search against the configured search base with the configured filter) in a KettleException with message key 'LDAPConnection.Error.Search'. The root cause is preserved as the cause, so the underlying LDAP error code (e.g. invalid DN, invalid filter, connection failure, size/time limit) is in e.getCause().
Solutions
- Inspect e.getCause() to get the real javax.naming exception (CommunicationException, NameNotFoundException, InvalidSearchFilterException, AuthenticationException) and fix accordingly.
- Validate the search base DN with ldapsearch, e.g. ldapsearch -H ldap://host -D user -w pass -b 'dc=example,dc=com' '(objectClass=*)'.
- Check the filter for balanced parentheses and a valid 'name=value' form.
- Verify host, port, username, password and SSL settings in the step/connection config.
- Test network reachability: telnet/nc to the LDAP port (389/636).
Example fix
// before
connection.setFilter("(objectClass");
// after
connection.setFilter("(objectClass=person)"); Defensive patterns
Strategy: try-catch
Validate before calling
// Validate before searching
if (searchBase == null || searchBase.trim().isEmpty()) throw new KettleException("Search base is empty");
if (filter == null || !balancedParentheses(filter)) throw new KettleException("Invalid LDAP filter: " + filter);
// then smoke-test with: ldapsearch -H ldap://host -D user -w pass -b "$searchBase" "$filter" Try / catch
try {
connection.search();
} catch (KettleException e) {
Throwable root = ExceptionUtils.getRootCause(e);
if (root instanceof CommunicationException) { /* fix host/port/SSL */ }
else if (root instanceof InvalidSearchFilterException) { /* fix filter */ }
else if (root instanceof NameNotFoundException) { /* fix search base DN */ }
else if (root instanceof AuthenticationException) { /* fix credentials */ }
throw e;
} Prevention
- Always validate base DN and filter with ldapsearch before configuring the step
- Keep credentials and SSL config in a shared, tested connection definition
- Log the root cause (e.getCause()) not just the Kettle message
- Verify network/firewall access to the LDAP port from the transformation host
When it happens
Trigger: Calling search() (directly or via getFields during transformation initialization) when: the search base DN does not exist or is malformed; the filter string is not a valid LDAP filter; the LDAP server is unreachable or credentials fail; search controls (scope, size limit, time limit) are invalid.
Common situations: Typo or trailing spaces in the Search Base DN (e.g. 'dc=example,dc=com' written as 'dc=example, dc=com' is fine but 'dc=example' is not); unbalanced parentheses in the filter like '(objectClass' instead of '(objectClass=*)'; searching with an attribute that doesn't exist combined with an invalid filter; firewall/SSL misconfiguration preventing connection; anonymous bind rejected by the directory.
Related errors
- LDAPConnection.Error.Delete
- LDAPConnection.Error.Insert
- LDAPConnection.Error.Update
- LDAPConnection.Error.Upsert
- LDAPConnection.Error.Add
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/3dee854a0406e419.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/ldap/impl/src/main/java/org/pentaho/di/trans/steps/ldapinput/LDAPConnection.java:270
}
}
if ( nrCtl > 0 ) {
Control[] ctls = new Control[nrCtl];
int index = 0;
if ( ctlk != null ) {
ctls[index++] = ctlk;
}
if ( ctlp != null ) {
ctls[index++] = ctlp;
}
getInitialContext().setRequestControls( ctls );
}
// Search for objects using the filter
this.results = getInitialContext().search( getSearchBase(), getFilter(), getSearchControls() );
} catch ( Exception e ) {
throw new KettleException( BaseMessages.getString( "LDAPConnection.Error.Search" ), e );
}
}
public int delete( String dn, boolean checkEntry ) throws KettleException {
try {
if ( checkEntry ) {
// First Check entry
getInitialContext().lookup( dn );
}
// The entry exists
getInitialContext().destroySubcontext( dn );
if ( log.isDebug() ) {
log.logDebug( BaseMessages.getString( PKG, "LDAPinput.Exception.Deleted", dn ) );
}
return STATUS_DELETED;
} catch ( NameNotFoundException n ) {
// The entry is not foundView on GitHub (pinned to f3058517a1)