pentaho/pentaho-kettle · error · KettleException
Unable to save job entry of type 'ftp' to the repository…
Error message
Unable to save job entry of type 'ftp' to the repository for id_job=
What it means
JobEntryFTP.saveRep() persists all FTP job-entry attributes to the Kettle repository. When any saveJobEntryAttribute call throws a KettleDatabaseException, it is wrapped in this KettleException naming the entry type and id_job. The original database exception is attached as the cause.
Solutions
- Check the repository database is reachable and the connection is valid before saving
- Inspect the cause (KettleDatabaseException) for the underlying SQL error and fix the schema/permissions
- Reconnect to the repository (re-login) and retry the save
- Verify the repository user has INSERT/UPDATE rights on the job attribute tables
Example fix
// before
jobEntry.saveRep(rep, metaStore, id_job);
// after
try {
jobEntry.saveRep(rep, metaStore, id_job);
} catch (KettleException e) {
logError("Repository save failed: " + e.getCause(), e);
rep.disconnect();
rep.connect(login, password);
jobEntry.saveRep(rep, metaStore, id_job);
} Defensive patterns
Strategy: try-catch
Validate before calling
if (rep == null || !rep.isConnected()) { throw new IllegalStateException("Repository not connected before save"); } Try / catch
try { entry.saveRep(rep, metaStore, id_job); } catch (KettleException e) { log.error("FTP entry save failed", e.getCause()); /* reconnect & retry */ } Prevention
- Verify repository connectivity before bulk saves
- Keep repository schema at the version matching your Pentaho runtime
- Grant the repository user write access to job attribute tables
- Log the cause chain, not just the wrapper message
When it happens
Trigger: Calling saveRep on a JobEntryFTP whose repository connection is down, the repository schema lacks the required attribute tables/columns, or a database-level constraint/IO error occurs while writing the FTP entry attributes.
Common situations: Repository database offline or networked DB unreachable during save; stale/corrupt repository connection after a long session; migrating repositories across versions with schema drift; permission problems on the repository user.
Related errors
- AbortMeta.Exception.UnableToSaveStepInfoToRepository
- Edi2Xml.Exception.UnableToSaveStepInfoToRepository
- ERROR_0002_Cannot_Load_Job_From_Repository
- ERROR_0002
- ERROR_0003_Cannot_Save_Job_Entry
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/598dd4f104658ab2.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/get-file-with-ftp/impl/src/main/java/org/pentaho/di/job/entries/ftp/JobEntryFTP.java:468
rep.saveJobEntryAttribute( id_job, getObjectId(), "isaddresult", isaddresult );
rep.saveJobEntryAttribute( id_job, getObjectId(), "createmovefolder", createmovefolder );
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", Encr
.encryptPasswordIfNotUsingVariables( proxyPassword ) );
rep.saveJobEntryAttribute( id_job, getObjectId(), "socksproxy_host", socksProxyHost );
rep.saveJobEntryAttribute( id_job, getObjectId(), "socksproxy_port", socksProxyPort );
rep.saveJobEntryAttribute( id_job, getObjectId(), "socksproxy_username", socksProxyUsername );
rep.saveJobEntryAttribute( id_job, getObjectId(), "socksproxy_password", Encr
.encryptPasswordIfNotUsingVariables( socksProxyPassword ) );
rep.saveJobEntryAttribute( id_job, getObjectId(), "ifFileExists", SifFileExists );
rep.saveJobEntryAttribute( id_job, getObjectId(), "nr_limit", nr_limit );
rep.saveJobEntryAttribute( id_job, getObjectId(), "success_condition", success_condition );
} catch ( KettleDatabaseException dbe ) {
throw new KettleException(
"Unable to save job entry of type 'ftp' to the repository for id_job=" + id_job, dbe );
}
}
public void setLimit( String nr_limitin ) {
this.nr_limit = nr_limitin;
}
public String getLimit() {
return nr_limit;
}
public void setSuccessCondition( String success_condition ) {
this.success_condition = success_condition;
}
public String getSuccessCondition() {
return success_condition;View on GitHub (pinned to f3058517a1)