pentaho/pentaho-kettle · error · KettleException

UserInfo.Error.SavingUser

Error message

UserInfo.Error.SavingUser

What it means

saveUserInfo() wraps all repository writes in a try/catch and rethrows any KettleDatabaseException as a generic KettleException 'UserInfo.Error.SavingUser <login>', preserving the cause. It means the insert/update of the user row into R_USER (or the commit) failed at the database level.

Solutions

  1. Check the chained cause (dbe) for the real SQL error
  2. Ensure the login is unique before saving (look up existing user first)
  3. Verify repository database connectivity, credentials, and that the schema is upgraded (RepositoryConnectController / upgrade scripts)

Example fix

// before
repo.userDelegate.saveUserInfo(userInfo);
// after
try {
  repo.userDelegate.saveUserInfo(userInfo);
} catch (KettleException e) {
  throw new KettleException("Failed to save user " + userInfo.getLogin() + ": " + e.getCause().getMessage(), e);
}
Defensive patterns

Strategy: try-catch

Validate before calling

ObjectId existing = repo.userDelegate.getUserID(userInfo.getLogin());
if (existing != null) throw new IllegalStateException("User already exists: " + userInfo.getLogin());

Try / catch

try { repo.userDelegate.saveUserInfo(userInfo); } catch (KettleException e) { throw new KettleException("Save user failed: " + e.getCause(), e); }

Prevention

When it happens

Trigger: repository.userDelegate.saveUserInfo(userInfo) or repository.save(userInfo) when insertTableRow/updateTableRow on R_USER throws KettleDatabaseException (duplicate login, constraint violation, connection failure, read-only DB).

Common situations: Creating a user whose login already exists in R_USER; repository database down or credentials changed; schema out of date after a Kettle version upgrade; disk full on the DB server.

Related errors


AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13). Data as JSON: /api/errors/d5a648d33b5a5311. Report an issue: GitHub.

Appendix: source

Thrown at engine/src/main/java/org/pentaho/di/repository/kdr/delegates/KettleDatabaseRepositoryUserDelegate.java:124

      // Do we have a user id already?
      if ( userInfo.getObjectId() == null ) {
        userInfo.setObjectId( getUserID( userInfo.getLogin() ) ); // Get userid in the repository
      }

      if ( userInfo.getObjectId() == null ) {
        // This means the login doesn't exist in the database
        // and we have no id, so we don't know the old one...
        // Just grab the next user ID and do an insert:
        userInfo.setObjectId( repository.connectionDelegate.getNextUserID() );
        repository.connectionDelegate.insertTableRow( "R_USER", fillTableRow( userInfo ) );
      } else {
        repository.connectionDelegate.updateTableRow( "R_USER", "ID_USER", fillTableRow( userInfo ) );
      }

      // Put a commit behind it!
      repository.commit();
    } catch ( KettleDatabaseException dbe ) {
      throw new KettleException(
        BaseMessages.getString( PKG, "UserInfo.Error.SavingUser", userInfo.getLogin() ), dbe );
    }

  }

  public RowMetaAndData fillTableRow( IUser userInfo ) {
    RowMetaAndData r = new RowMetaAndData();
    r.addValue( new ValueMetaInteger( "ID_USER" ), userInfo.getObjectId() );
    r.addValue( new ValueMetaString( "LOGIN" ), userInfo.getLogin() );
    r.addValue( new ValueMetaString( "PASSWORD" ), Encr.encryptPassword( userInfo
      .getPassword() ) );
    r.addValue( new ValueMetaString( "NAME" ), userInfo.getUsername() );
    r.addValue( new ValueMetaString( "DESCRIPTION" ), userInfo.getDescription() );
    r.addValue( new ValueMetaBoolean( "ENABLED" ), Boolean.valueOf( userInfo.isEnabled() ) );
    return r;
  }

  public synchronized int getNrUsers() throws KettleException {

View on GitHub (pinned to f3058517a1)