theonedev/onedev · error · ExplicitException

Unable to find job:

Error message

Unable to find job: 

What it means

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.

Source

Thrown at server-core/src/main/java/io/onedev/server/web/component/pipeline/JobIndex.java:42

	}
	
	public int getColumn() {
		return column;
	}

	public int getRow() {
		return row;
	}

	public static JobIndex of(List<List<Job>> pipeline, Job job) {
		for (int columnIndex = 0; columnIndex < pipeline.size(); columnIndex++) {
			List<Job> column = pipeline.get(columnIndex);
			for (int rowIndex = 0; rowIndex < column.size(); rowIndex++) {
				if (column.get(rowIndex).equals(job)) 
					return new JobIndex(columnIndex, rowIndex);
			}
		}
		throw new ExplicitException("Unable to find job: " + job.getName());
	}
	
	public Job getJob(List<List<Job>> pipeline) {
		return pipeline.get(column).get(row);
	}
	
	public String toJson() {
		try {
			return OneDev.getInstance(ObjectMapper.class).writeValueAsString(this);
		} catch (JsonProcessingException e) {
			throw new RuntimeException(e);
		}
	}
	
	@Override
	public String toString() {
		return column + "-" + row;
	}

View on GitHub (pinned to d44925c47c)

Solutions

  1. Ensure the Job instance passed to of() comes from the same pipeline object being searched.
  2. Compare by job name/identifier if instances may come from different persistence contexts.
  3. Check whether the build spec was recently edited and the job was removed or renamed.
  4. Reload the pipeline from the current build spec before indexing the job.

Example fix

// before
JobIndex index = JobIndex.of(pipeline, otherPipelineJob);
// after
if (pipeline.getJobs().stream().anyMatch(j -> j.equals(job))) {
    JobIndex index = JobIndex.of(pipeline, job);
}
Defensive patterns

Strategy: validation

Validate before calling

boolean present = pipeline.stream().flatMap(List::stream).anyMatch(j -> j.equals(job));
if (!present) throw new IllegalArgumentException("job not in pipeline");

Type guard

boolean jobInPipeline = pipeline.stream().flatMap(List::stream).anyMatch(job::equals);

Try / catch

try { return JobIndex.of(pipeline, job); } catch (ExplicitException e) { throw new IllegalArgumentException("Job '" + job.getName() + "' does not belong to the pipeline", e); }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.

Related errors


AI-assisted analysis of theonedev/onedev@d44925c47c (2026-09-06). Data as JSON: /api/errors/694a9cb95e8ebff4. Report an issue: GitHub.