pentaho/pentaho-kettle · error · KettleException
JobHopMeta.Exception.UnableToLoadHopInfoRep
Error message
JobHopMeta.Exception.UnableToLoadHopInfoRep
What it means
Thrown by loadJobHopMeta when a KettleDatabaseException occurs while reading hop information (r_jobhop row and its referenced job entry copies) from the repository. The localized message 'UnableToLoadHopInfoRep' with the hop ID wraps the database cause. Unlike error 1053 this is a read/query failure, not an empty result.
Solutions
- Check the wrapped cause (e.getCause()) for the concrete KettleDatabaseException and address the DB issue.
- Verify the hop's referenced job entry copies still exist in r_jobentry; delete dangling hop rows if entries are gone.
- Align repository schema version with the client (run upgrade/repair scripts).
- Reconnect/retry if the failure was a transient connection drop during load.
Example fix
// before: ignoring the wrapped cause
} catch (KettleException e) {
log.warn(e.getMessage());
}
// after: log cause chain to identify the SQL problem
} catch (KettleException e) {
log.warn("Hop load failed: " + e.getMessage(), e.getCause());
} Defensive patterns
Strategy: try-catch
Validate before calling
// check referenced entries exist before loading the hop
boolean entriesExist =
repo.connectionDelegate.countNonZero(
"SELECT COUNT(*) FROM R_JOBENTRY WHERE ID_JOBENTRY IN (?, ?)",
Arrays.asList(idFrom, idTo)) == 2;
if (!entriesExist) throw new IllegalStateException("Hop references deleted job entries"); Type guard
boolean isLoadableHop(ObjectId hopId) {
return hopId != null && hopId.getId() != null && ((Number) hopId.getId()).longValue() > 0;
} Try / catch
try {
hop = repo.loadJobHopMeta(hopId);
} catch (KettleException e) {
Throwable root = e;
while (root.getCause() != null) root = root.getCause();
if (root instanceof KettleDatabaseException && isTransient(root)) {
repo.connect(); hop = repo.loadJobHopMeta(hopId); // retry after reconnect
} else {
throw e; // schema drift / dangling references need repair, not retry
}
} Prevention
- Keep client and repository schema versions aligned to avoid SQL/schema mismatches.
- Delete hop rows when their job entries are removed to prevent broken references.
- Unwrap e.getCause() to see the KettleDatabaseException before deciding on retry vs repair.
- Monitor DB connectivity (timeouts, permission errors) in long-running spoon/scheduler sessions.
When it happens
Trigger: Calling repository.loadJobHopMeta(id) when the SQL select on r_jobhop (or resolving id_jobentry_copy_from/to via findJobEntryCopy) throws — broken connection, SQL syntax/schema mismatch, or dangling references to deleted job entry copies causing lookup failures.
Common situations: Orphaned hop rows whose from/to job entries were deleted (violating expected joins); repository schema drift between client and DB versions; connection failure mid-load; DB permission problems reading r_jobhop.
Understand the failure class
Background: Database query failed: Internal Server Error 500s wrapping SQL, Prisma, and connection failures — what to check first — this error's family across 16 libraries.
Related errors
- JobHopMeta.Exception.UnableToSaveHopInfoRep
- JobMeta.Exception.AnErrorOccuredReadingJob
- AbortMeta.Exception.UnableToSaveStepInfoToRepository
- AccessInputMeta.Exception.ErrorReadingRepository
- AddSequenceMeta.Exception.UnableToReadStepInfo
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/571bb58b5de43fb8.
Report an issue: GitHub.
Appendix: source
Thrown at engine/src/main/java/org/pentaho/di/repository/kdr/delegates/KettleDatabaseRepositoryJobDelegate.java:654
long id_jobentry_copy_from = r.getInteger( "ID_JOBENTRY_COPY_FROM", -1L );
long id_jobentry_copy_to = r.getInteger( "ID_JOBENTRY_COPY_TO", -1L );
jobHopMeta.setEnabled( r.getBoolean( "ENABLED", true ) );
jobHopMeta.setEvaluation( r.getBoolean( "EVALUATION", true ) );
jobHopMeta.setConditional();
if ( r.getBoolean( "UNCONDITIONAL", !jobHopMeta.getEvaluation() ) ) {
jobHopMeta.setUnconditional();
}
jobHopMeta.setFromEntry( JobMeta.findJobEntryCopy( jobcopies, new LongObjectId( id_jobentry_copy_from ) ) );
jobHopMeta.setToEntry( JobMeta.findJobEntryCopy( jobcopies, new LongObjectId( id_jobentry_copy_to ) ) );
return jobHopMeta;
} else {
throw new KettleException( "Unable to find job hop with ID : " + id_job_hop );
}
} catch ( KettleDatabaseException dbe ) {
throw new KettleException( BaseMessages.getString( PKG, "JobHopMeta.Exception.UnableToLoadHopInfoRep", ""
+ 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 ) {View on GitHub (pinned to f3058517a1)