theonedev/onedev · error · ExplicitException

No applicable executor discovered for current job

Error message

No applicable executor discovered for current job

What it means

Thrown by DefaultJobService.getJobExecutor when no explicit executor is named and none of the globally configured, enabled job executors pass isApplicable for the current build. OneDev iterates all executors in order, logs 'Discovered ...' for the first match, and throws this ExplicitException only after exhausting the list.

Source

Thrown at server-core/src/main/java/io/onedev/server/job/DefaultJobService.java:548

				return settingService.getJobExecutors().stream()
					.filter(it -> it.isEnabled() && isApplicable(build, it))
					.findFirst()
					.orElseThrow(() -> new ExplicitException("No applicable job executor"));
			} else {
				jobLogger.log("No job executor defined, auto-discovering...");
				List<JobExecutorDiscoverer> discoverers = new ArrayList<>(OneDev.getExtensions(JobExecutorDiscoverer.class));
				discoverers.sort(Comparator.comparing(JobExecutorDiscoverer::getOrder));
				for (var discoverer : discoverers) {
					JobExecutor jobExecutor = discoverer.discover();
					if (jobExecutor != null) {
						jobExecutor.setName("auto-discovered");
						if (isApplicable(build, jobExecutor)) {
							jobLogger.log("Discovered " + EditableUtils.getDisplayName(jobExecutor.getClass()).toLowerCase());
							return jobExecutor;
						}
					}
				}
				throw new ExplicitException("No applicable executor discovered for current job");
			}
		}
	}

	private Future<Boolean> execute(Build build) {		
		String jobToken = build.getToken();
		JobVariableInterpolator interpolator = new JobVariableInterpolator(build, build.getParamCombination());

		TaskLogger jobLogger = logService.newLogger(build.getLoggingSupport());
		String jobExecutorName = interpolator.interpolate(build.getJob().getJobExecutor());
		JobExecutor jobExecutor = interpolator.interpolateProperties(getJobExecutor(build, jobExecutorName, jobLogger));
		String sequentialGroup = interpolator.interpolate(build.getJob().getSequentialGroup());
		String sequentialKey;
		if (sequentialGroup != null)
			sequentialKey = jobExecutorName + ":" + sequentialGroup;
		else
			sequentialKey = null;
		Long projectId = build.getProject().getId();

View on GitHub (pinned to d44925c47c)

Solutions

  1. Enable at least one job executor in Server Setting > Job Executors and ensure its criteria match this job.
  2. Register/bring online the required runners (docker host, k8s cluster, remote agent).
  3. Broaden executor criteria so they apply to this project/branch/job.
  4. Name a specific executor in the build spec if auto-discovery ordering is the problem.

Example fix

// Admin: Server Setting > Job Executors > Add Executor
// e.g. add a Docker Executor with project criteria '*' and enable it,
// then verify a runner is registered:
// Admin > Runners/Agents > Add Runner, use the token in your docker agent container
Defensive patterns

Strategy: validation

Validate before calling

// Java: verify at least one enabled executor applies before queueing jobs
boolean anyApplicable = OneDev.getInstance(SettingService.class)
        .getJobExecutors().stream()
        .anyMatch(it -> it.isEnabled());
if (!anyApplicable) {
    throw new IllegalStateException("No enabled job executors configured");
}

Try / catch

try {
    jobService.submit(build);
} catch (ExplicitException e) {
    if (e.getMessage().contains("No applicable executor")) {
        // alert admins to enable/register executors; retry after config fix
    }
}

Prevention

When it happens

Trigger: Submitting a job when settingService.getJobExecutors() is non-empty but every executor is either disabled or not applicable (wrong project/branch/job criteria, no registered runners), or the executor list is empty of usable entries for the job.

Common situations: Fresh OneDev instance with default executors only and the job requires Docker/K8s; all runners offline; executors all scoped to other projects/branches; admin disabled executors during maintenance while CI jobs keep being submitted.

Understand the failure class

Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.

Related errors


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