{"record":{"id":"694a9cb95e8ebff4","repo":"theonedev/onedev","slug":"unable-to-find-job","errorCode":null,"errorMessage":"Unable to find job: ","messagePattern":"Unable to find job: ","errorType":"exception","errorClass":"ExplicitException","httpStatus":null,"severity":"error","filePath":"server-core/src/main/java/io/onedev/server/web/component/pipeline/JobIndex.java","lineNumber":42,"sourceCode":"\t}\n\t\n\tpublic int getColumn() {\n\t\treturn column;\n\t}\n\n\tpublic int getRow() {\n\t\treturn row;\n\t}\n\n\tpublic static JobIndex of(List<List<Job>> pipeline, Job job) {\n\t\tfor (int columnIndex = 0; columnIndex < pipeline.size(); columnIndex++) {\n\t\t\tList<Job> column = pipeline.get(columnIndex);\n\t\t\tfor (int rowIndex = 0; rowIndex < column.size(); rowIndex++) {\n\t\t\t\tif (column.get(rowIndex).equals(job)) \n\t\t\t\t\treturn new JobIndex(columnIndex, rowIndex);\n\t\t\t}\n\t\t}\n\t\tthrow new ExplicitException(\"Unable to find job: \" + job.getName());\n\t}\n\t\n\tpublic Job getJob(List<List<Job>> pipeline) {\n\t\treturn pipeline.get(column).get(row);\n\t}\n\t\n\tpublic String toJson() {\n\t\ttry {\n\t\t\treturn OneDev.getInstance(ObjectMapper.class).writeValueAsString(this);\n\t\t} catch (JsonProcessingException e) {\n\t\t\tthrow new RuntimeException(e);\n\t\t}\n\t}\n\t\n\t@Override\n\tpublic String toString() {\n\t\treturn column + \"-\" + row;\n\t}","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/theonedev/onedev/blob/d44925c47c37992c828ea673a5f9620539bc3ff2/server-core/src/main/java/io/onedev/server/web/component/pipeline/JobIndex.java#L24-L60","documentation":"JobIndex.of(pipeline, job) searches every column of the pipeline's job matrix for the given Job instance using equals(). If the job is not present in any column it throws an ExplicitException. It is an internal invariant: only jobs belonging to the pipeline are expected to be indexed.","triggerScenarios":"Calling JobIndex.of(pipeline, job) with a Job instance that is not contained (by equals) in any list of the pipeline matrix, e.g. a job from a different pipeline or a stale/detached entity instance.","commonSituations":"Passing a Job loaded from a different session so equals() fails against the pipeline's in-memory jobs; referencing a job that was removed from the pipeline in a build spec edit; a plugin constructing a JobIndex for a job that never existed in this pipeline.","solutions":["Ensure the Job instance passed to of() comes from the same pipeline object being searched.","Compare by job name/identifier if instances may come from different persistence contexts.","Check whether the build spec was recently edited and the job was removed or renamed.","Reload the pipeline from the current build spec before indexing the job."],"exampleFix":"// before\nJobIndex index = JobIndex.of(pipeline, otherPipelineJob);\n// after\nif (pipeline.getJobs().stream().anyMatch(j -> j.equals(job))) {\n    JobIndex index = JobIndex.of(pipeline, job);\n}","handlingStrategy":"validation","validationCode":"boolean present = pipeline.stream().flatMap(List::stream).anyMatch(j -> j.equals(job));\nif (!present) throw new IllegalArgumentException(\"job not in pipeline\");","typeGuard":"boolean jobInPipeline = pipeline.stream().flatMap(List::stream).anyMatch(job::equals);","tryCatchPattern":"try { return JobIndex.of(pipeline, job); } catch (ExplicitException e) { throw new IllegalArgumentException(\"Job '\" + job.getName() + \"' does not belong to the pipeline\", e); }","preventionTips":["Only pass Job instances sourced from the same pipeline object","Compare jobs by stable identity/name when crossing persistence boundaries","Re-resolve the pipeline after build spec edits"],"tags":["pipeline","entity-not-found","internal-invariant"],"backgroundTag":"record-not-found","analyzedSha":"d44925c47c37992c828ea673a5f9620539bc3ff2","analyzedAt":"2026-09-06T07:18:27.995Z","contentChangedAt":"2026-09-06T07:18:27.995Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}