pentaho/pentaho-kettle · error · KettleException

JobFTPSPUT.UnableToSaveToRepo

JobFTPSPUT.UnableToSaveToRepo

Error message

JobFTPSPUT.UnableToSaveToRepo

What it means

JobEntryFTPSPUT.saveRep() throws this KettleException when persisting the entry's attributes (including connection_type) to the repository fails with a KettleDatabaseException. It is rethrown with the JobFTPSPUT.UnableToSaveToRepo message and the id_job identifier, with the database exception preserved as cause — typically a repository write/transaction problem rather than a config error.

Solutions

  1. Check the cause KettleDatabaseException for the SQL error and fix the repository database issue (connectivity, disk, locks).
  2. Verify the repository user has write permission on r_jobentry_attribute.
  3. Retry the save after confirming the repository is online; if corrupt, re-save the job from a fresh connection.
  4. Test the repository connection in Spoon (Connect/Test) before saving large jobs.

Example fix

// before: saving without checking repository availability
jobEntry.saveRep( rep, metaStore, id_job );
// after: verify connection first
if ( !rep.getConnection().equals( ... ) && !rep.testConnection() ) {
  throw new KettleException( "Repository unavailable" );
}
jobEntry.saveRep( rep, metaStore, id_job );
Defensive patterns

Strategy: try-catch

Validate before calling

// check repository writability before saving
if ( !rep.isConnected() ) throw new KettleException( "Repository not connected" );
// optionally run: rep.testConnection(); or a cheap write probe

Try / catch

try {
  entry.saveRep( rep, metaStore, id_job );
} catch ( KettleException e ) {
  Throwable c = e.getCause();
  log.error( "Repo save failed for FTPSPUT entry: " + ( c != null ? c.getMessage() : e.getMessage() ) );
  throw new KettleException( "Fix repository DB issue (connection/privileges/space) and retry save", e );
}

Prevention

When it happens

Trigger: Calling saveRep() during job save when the repository connection is broken, the database is read-only or out of space, a constraint on r_jobentry_attribute is violated, or the transaction rolls back mid-save.

Common situations: Repository database down or networked DB dropped mid-save; user lacks INSERT/UPDATE rights on repository tables; database in read-only mode (maintenance, disk full); concurrent modification locking issues.

Related errors


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

Appendix: source

Thrown at plugins/ftps/impl/src/main/java/org/pentaho/di/job/entries/ftpsput/JobEntryFTPSPUT.java:221

        .encryptPasswordIfNotUsingVariables( password ) );
      rep.saveJobEntryAttribute( id_job, getObjectId(), "remoteDirectory", remoteDirectory );
      rep.saveJobEntryAttribute( id_job, getObjectId(), "localDirectory", localDirectory );
      rep.saveJobEntryAttribute( id_job, getObjectId(), "wildcard", wildcard );
      rep.saveJobEntryAttribute( id_job, getObjectId(), "binary", binaryMode );
      rep.saveJobEntryAttribute( id_job, getObjectId(), "timeout", timeout );
      rep.saveJobEntryAttribute( id_job, getObjectId(), "remove", remove );
      rep.saveJobEntryAttribute( id_job, getObjectId(), "only_new", onlyPuttingNewFiles );
      rep.saveJobEntryAttribute( id_job, getObjectId(), "active", activeConnection );

      rep.saveJobEntryAttribute( id_job, getObjectId(), "proxy_host", proxyHost );
      rep.saveJobEntryAttribute( id_job, getObjectId(), "proxy_port", proxyPort );
      rep.saveJobEntryAttribute( id_job, getObjectId(), "proxy_username", proxyUsername );
      rep.saveJobEntryAttribute( id_job, getObjectId(), "proxy_password", proxyPassword );
      rep.saveJobEntryAttribute( id_job, getObjectId(), "connection_type", FTPSConnection
        .getConnectionType( connectionType ) );

    } catch ( KettleDatabaseException dbe ) {
      throw new KettleException( BaseMessages.getString( PKG, "JobFTPSPUT.UnableToSaveToRepo", String
        .valueOf( id_job ) ), dbe );
    }
  }

  /**
   * @return Returns the binaryMode.
   */
  public boolean isBinaryMode() {
    return binaryMode;
  }

  /**
   * @param binaryMode
   *          The binaryMode to set.
   */
  public void setBinaryMode( boolean binaryMode ) {
    this.binaryMode = binaryMode;
  }

View on GitHub (pinned to f3058517a1)