pentaho/pentaho-kettle · error · KettleException
JobHopMeta.Exception.UnableToSaveHopInfoRep
Error message
JobHopMeta.Exception.UnableToSaveHopInfoRep
What it means
KettleDatabaseRepositoryJobDelegate.saveJobHopMeta wraps a KettleDatabaseException thrown while inserting a job hop row into the Kettle database repository tables (R_JOB_HOP). The wrapper includes the internal job id for debugging and chains the underlying database exception as the cause. It means the hop could not be persisted during job save.
Solutions
- Check the chained KettleDatabaseException cause for the real database error (constraint, missing table, connection).
- Verify the repository schema version matches your Kettle/Pentaho version and run the repository upgrade/repair if needed.
- Ensure all job entries save successfully before the hop (fix earlier save errors on the job entries).
- Test repository connectivity (db connection, credentials, network) and retry the save after restoring the connection.
Example fix
// before
repository.save(job, versionComment, null, null); // fails mid-way with hop save error
// after
try {
repository.save(job, versionComment, null, null);
} catch (KettleException e) {
logError("Job save failed: " + e.getCause(), e); // inspect KettleDatabaseException cause
// repair repository connection/schema, then retry
} Defensive patterns
Strategy: try-catch
Validate before calling
if (!repository.isConnected()) throw new IllegalStateException("Repository not connected");
if (hop.getObjectId() == null) { /* ensure from/to job entries already saved with valid ids */ }
// also verify repository schema version:
// repository.getRepositoryMeta().getRepositoryVersion() vs expected Kettle version Try / catch
try {
repository.save(job, versionComment, null, null);
} catch (KettleException e) {
Throwable cause = e.getCause();
if (cause instanceof KettleDatabaseException) {
logError("Hop persistence failed: " + cause.getMessage(), cause);
}
// restore connection / fix schema, then retry
} Prevention
- Always save job entries before saving hops so their object ids are valid.
- Keep repository schema upgraded to match your Kettle version.
- Monitor repository DB connectivity before batch saves.
- Log and inspect the chained cause on every repository save failure.
When it happens
Trigger: Calling repository.save(job, ...) (or KettleDatabaseRepository.saveJob) when insertJobHop fails: e.g. the referenced job entries (id_jobentry_from/to) were not yet saved (null/invalid object ids), the repository table R_JOB_HOP is missing/corrupt, a database constraint violation occurs (duplicate hop, NULL in required column), or the repository connection was lost.
Common situations: Saving a job in Spoon against a database repository whose schema was not upgraded to the current Pentaho/Kettle version; network/DB outage mid-save; a job hop pointing to a job entry that failed to save; duplicate or self-referencing hop entries violating constraints.
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/93ac563cbb21b375.
Report an issue: GitHub.
Appendix: source
Thrown at engine/src/main/java/org/pentaho/di/repository/kdr/delegates/KettleDatabaseRepositoryJobDelegate.java:673
+ id_job_hop ), dbe );
}
}
public void saveJobHopMeta( JobHopMeta hop, ObjectId id_job ) throws KettleException {
try {
ObjectId id_jobentry_from = null;
ObjectId id_jobentry_to = null;
id_jobentry_from = hop.getFromEntry() == null ? null : hop.getFromEntry().getObjectId();
id_jobentry_to = hop.getToEntry() == null ? null : hop.getToEntry().getObjectId();
// Insert new job hop in repository
//
hop.setObjectId( insertJobHop( id_job, id_jobentry_from, id_jobentry_to, hop.isEnabled(), hop
.getEvaluation(), hop.isUnconditional() ) );
} catch ( KettleDatabaseException dbe ) {
throw new KettleException( BaseMessages.getString( PKG, "JobHopMeta.Exception.UnableToSaveHopInfoRep", ""
+ id_job ), dbe );
}
}
/**
* Read the database connections in the repository and add them to this job if they are not yet present.
*
* @param jobMeta
* the job to put the database connections in
* @throws KettleException
*/
public void readDatabases( JobMeta jobMeta ) throws KettleException {
readDatabases( jobMeta, true );
}
/**
* Read the database connections in the repository and add them to this job if they are not yet present.View on GitHub (pinned to f3058517a1)