{"record":{"id":"ade91d35a3f2cd9c","repo":"pentaho/pentaho-kettle","slug":"ldapconnection-error-upsert","errorCode":"LDAPConnection.Error.Upsert","errorMessage":"LDAPConnection.Error.Upsert","messagePattern":"LDAPConnection\\.Error\\.Upsert","errorType":"exception","errorClass":"KettleException","httpStatus":null,"severity":"error","filePath":"plugins/ldap/impl/src/main/java/org/pentaho/di/trans/steps/ldapinput/LDAPConnection.java","lineNumber":417,"sourceCode":"      try {\n        getInitialContext().getAttributes( dn );\n        found = true;\n      } catch ( NameNotFoundException n ) {\n        Attributes attrs = buildAttributes( dn, attributes, values, multValuedSeparator );\n        getInitialContext().createSubcontext( dn, attrs );\n        return STATUS_INSERTED;\n      }\n\n      if ( found && attributesToUpdate != null && attributesToUpdate.length > 0 ) {\n        // The entry already exist\n        // let's update\n        Attributes attrs = buildAttributes( dn, attributesToUpdate, valuesToUpdate, multValuedSeparator );\n        getInitialContext().modifyAttributes( dn, DirContext.REPLACE_ATTRIBUTE, attrs );\n        return STATUS_UPDATED;\n      }\n\n    } catch ( Exception e ) {\n      throw new KettleException( BaseMessages.getString( PKG, \"LDAPConnection.Error.Upsert\", dn ), e );\n    }\n    return STATUS_SKIPPED;\n  }\n\n  private Attributes buildAttributes( String dn, String[] attributes, String[] values, String multValuedSeparator ) {\n    Attributes attrs = new javax.naming.directory.BasicAttributes( true );\n    int nrAttributes = attributes.length;\n    for ( int i = 0; i < nrAttributes; i++ ) {\n      if ( !Utils.isEmpty( values[i] ) ) {\n        // We have a value\n        String value = values[i].trim();\n        if ( multValuedSeparator != null && value.indexOf( multValuedSeparator ) > 0 ) {\n          Attribute attr = new javax.naming.directory.BasicAttribute( attributes[i] );\n          for ( String attribute : value.split( multValuedSeparator ) ) {\n            attr.add( attribute );\n          }\n          attrs.put( attr );\n        } else {","sourceCodeStart":399,"sourceCodeEnd":435,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/plugins/ldap/impl/src/main/java/org/pentaho/di/trans/steps/ldapinput/LDAPConnection.java#L399-L435","documentation":"LDAPConnection.upsert(dn, attributesToUpdate, valuesToUpdate, multValuedSeparator) performs a lookup of the DN and either adds it (createSubcontext) or replaces its attributes (modifyAttributes REPLACE_ATTRIBUTE). Any exception in either path is wrapped in a KettleException with message key 'LDAPConnection.Error.Upsert' (dn interpolated), with the JNDI exception as cause.","triggerScenarios":"Upsert where the parent OU for a new entry doesn't exist; replace on a DN whose attributes violate schema; permission failures on create or modify; connection/authentication loss; invalid DN syntax.","commonSituations":"Mixed create/update runs where the bind account can modify but not create (or vice versa); mandatory objectClass attributes missing on insert path; single-valued attribute receiving multiple values on replace.","solutions":["Inspect e.getCause() to tell whether the failure was on the insert or the modify path.","Ensure the parent OU exists before upserting new entries.","Verify bind account has both create and write rights on the target subtree.","Validate attributes/values against the objectClass schema (required and allowed attributes).","Escape DN special characters before calling upsert."],"exampleFix":"// before\nconnection.upsert(dn, attrs, vals, \";\"); // parent OU may not exist\n// after\nensureOuDExists(connection, \"ou=people,dc=example,dc=com\");\nconnection.upsert(dn, attrs, vals, \";\");","handlingStrategy":"try-catch","validationCode":"// Pre-flight: verify parent OU and bind account rights\nString parentDn = dn.substring(dn.indexOf(\",\") + 1);\nconnection.setSearchBase(parentDn);\nconnection.setFilter(\"(objectClass=*)\");\nconnection.search(); // empty => parent OU missing, create it before upsert","typeGuard":null,"tryCatchPattern":"try {\n  connection.upsert(dn, attrs, vals, \";\");\n} catch (KettleException e) {\n  Throwable root = ExceptionUtils.getRootCause(e);\n  if (root instanceof NoPermissionException) { /* grant create+write rights */ }\n  else if (root instanceof SchemaViolationException) { /* fix attributes vs objectClass */ }\n  throw e;\n}","preventionTips":["Ensure the bind account has BOTH create and modify rights (upsert uses either path)","Create parent OUs before running upserts against new subtrees","Validate attribute/value syntax against the schema","Log the root cause to distinguish insert-path vs update-path failures"],"tags":["ldap","kettle","upsert","jndi"],"backgroundTag":"database-write-failed","analyzedSha":"f3058517a153da500bf4551f46d79b91bf8ec552","analyzedAt":"2026-09-13T14:04:16.340Z","contentChangedAt":"2026-09-13T14:04:16.340Z","schemaVersion":2},"datasetVersion":"2026-09-20T23:17:15.980Z"}