{"record":{"id":"54f9488193cabff8","repo":"pentaho/pentaho-kettle","slug":"unable-to-find-job-hop-with-id-id-job-hop","errorCode":null,"errorMessage":"Unable to find job hop with ID : id_job_hop","messagePattern":"Unable to find job hop with ID : id_job_hop","errorType":"exception","errorClass":"KettleException","httpStatus":null,"severity":"error","filePath":"engine/src/main/java/org/pentaho/di/repository/kdr/delegates/KettleDatabaseRepositoryJobDelegate.java","lineNumber":651,"sourceCode":"    try {\n      RowMetaAndData r = getJobHop( id_job_hop );\n      if ( r != null ) {\n        long id_jobentry_copy_from = r.getInteger( \"ID_JOBENTRY_COPY_FROM\", -1L );\n        long id_jobentry_copy_to = r.getInteger( \"ID_JOBENTRY_COPY_TO\", -1L );\n\n        jobHopMeta.setEnabled( r.getBoolean( \"ENABLED\", true ) );\n        jobHopMeta.setEvaluation( r.getBoolean( \"EVALUATION\", true ) );\n        jobHopMeta.setConditional();\n        if ( r.getBoolean( \"UNCONDITIONAL\", !jobHopMeta.getEvaluation() ) ) {\n          jobHopMeta.setUnconditional();\n        }\n\n        jobHopMeta.setFromEntry( JobMeta.findJobEntryCopy( jobcopies, new LongObjectId( id_jobentry_copy_from ) ) );\n        jobHopMeta.setToEntry( JobMeta.findJobEntryCopy( jobcopies, new LongObjectId( id_jobentry_copy_to ) ) );\n\n        return jobHopMeta;\n      } else {\n        throw new KettleException( \"Unable to find job hop with ID : \" + id_job_hop );\n      }\n    } catch ( KettleDatabaseException dbe ) {\n      throw new KettleException( BaseMessages.getString( PKG, \"JobHopMeta.Exception.UnableToLoadHopInfoRep\", \"\"\n        + id_job_hop ), dbe );\n\n    }\n  }\n\n  public void saveJobHopMeta( JobHopMeta hop, ObjectId id_job ) throws KettleException {\n    try {\n      ObjectId id_jobentry_from = null;\n      ObjectId id_jobentry_to = null;\n\n      id_jobentry_from = hop.getFromEntry() == null ? null : hop.getFromEntry().getObjectId();\n      id_jobentry_to = hop.getToEntry() == null ? null : hop.getToEntry().getObjectId();\n\n      // Insert new job hop in repository\n      //","sourceCodeStart":633,"sourceCodeEnd":669,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/engine/src/main/java/org/pentaho/di/repository/kdr/delegates/KettleDatabaseRepositoryJobDelegate.java#L633-L669","documentation":"Thrown by loadJobHopMeta when a hop is requested by id_job_hop but the repository lookup returns no row, so the hop cannot be found by its ID. The loaded hop would be null otherwise; this explicit error surfaces the missing record instead of returning null.","triggerScenarios":"Calling repository.loadJobHopMeta(ObjectId id_job_hop) with an ObjectId that has no matching row in r_jobhop — e.g. an ID from a stale/cached job copy, an ID from another repository, or a hop deleted by another user.","commonSituations":"Concurrent editing where one session deleted hops another session still references; loading a job whose hop rows were removed by a failed transaction; passing an id from a legacy/renumbered repository.","solutions":["Re-save/reload the job from the repository so hop IDs are current, then retry loading the hop.","Verify the ObjectId actually came from the same repository database.","Remove the dangling hop reference from the job and re-save it.","Check r_jobhop directly in the DB to confirm the row is missing before assuming client bugs."],"exampleFix":"// before: trusting cached hop IDs\njobHop = repo.loadJobHopMeta(new LongObjectId(cachedHopId));\n\n// after: refresh the job to get valid hop IDs\nJobMeta fresh = repo.loadJobMeta(\"MyJob\", dir, null);\nfor (JobHopMeta hop : fresh.getJobhops()) {\n  jobHop = repo.loadJobHopMeta(hop.getObjectId());\n}","handlingStrategy":"validation","validationCode":"// confirm the hop ID exists before loading\nList<ObjectId[]> rows = repo.connectionDelegate.getRows(\n  \"SELECT ID_JOBHOP FROM \" + repository.getDatabaseMeta().getQuotedSchemaTableCombination(null, \"R_JOBHOP\")\n  + \" WHERE ID_JOBHOP = ?\", Collections.singletonList(hopId), 1);\nif (rows.isEmpty()) throw new IllegalStateException(\"Hop \" + hopId + \" no longer exists in repository\");","typeGuard":"boolean isFreshHopId(JobHopMeta hop, JobMeta currentJob) {\n  return hop != null && hop.getObjectId() != null\n      && currentJob.getJobhops().stream().anyMatch(h -> hop.getObjectId().equals(h.getObjectId()));\n}","tryCatchPattern":"try {\n  hop = repo.loadJobHopMeta(hopId);\n} catch (KettleException e) {\n  if (e.getMessage().startsWith(\"Unable to find job hop\")) {\n    // stale ID: reload the job and drop the dangling reference\n    jobMeta = repo.loadJobMeta(jobname, dir, null);\n  } else { throw e; }\n}","preventionTips":["Reload the owning job before using hop ObjectIds cached from earlier sessions.","Never carry ObjectIds across repositories or environments.","Avoid concurrent edits; use repository versioning/locking where available.","Clean up dangling hops when deleting job entries (delete hops referencing the entry first)."],"tags":["repository","job-hop","not-found","stale-reference"],"backgroundTag":"record-not-found","analyzedSha":"f3058517a153da500bf4551f46d79b91bf8ec552","analyzedAt":"2026-09-13T14:04:16.340Z","contentChangedAt":"2026-09-13T14:04:16.340Z","schemaVersion":2},"datasetVersion":"2026-09-20T23:17:15.980Z"}