theonedev/onedev · error · ExplicitException

Specified job executor '" + jobExecutorName + "' is not…

Error message

Specified job executor '" + jobExecutorName + "' is not applicable for current job

What it means

Thrown by DefaultJobService.getJobExecutor when the job spec names an enabled executor whose isApplicable(build, jobExecutor) check fails — i.e., the executor's criteria (project, job name, branch/tag, ref filters, runner capability) do not match the current build. The executor exists and is enabled, but it cannot run this particular job.

Solutions

  1. Broaden the executor's criteria in Server Setting > Job Executors (project/branch/job filters) to include this job.
  2. Change the job spec to name an executor whose criteria match this build.
  3. Remove the explicit executor name to let auto-discovery pick any applicable enabled executor.
  4. Register the required runner/agent so the executor's capacity requirements are satisfied.

Example fix

// before: executor scoped to main branch only, job on feature branch
// after (build spec): omit executor name for auto-discovery
jobs:
  - name: Build
    steps: !<CommandLine>
      shellScript: mvn package
Defensive patterns

Strategy: validation

Validate before calling

// Confirm the named executor's criteria include this project/branch/job
// before referencing it in .onedev-buildspec.yml:
// Admin > Job Executors > <name> : check project/branch/job criteria
// and required capabilities for the job being submitted

Try / catch

try {
    jobService.submit(build);
} catch (ExplicitException e) {
    if (e.getMessage().contains("is not applicable")) {
        // broaden executor criteria or drop the explicit executor name
    }
}

Prevention

When it happens

Trigger: Specifying 'executor: <name>' where that executor defines applicability criteria (e.g., restricted to certain projects, branches, job names, or requires a registered runner) that the current build/job does not satisfy; then jobExecutor -> getJobExecutor throws.

Common situations: Executor narrowed to main branch while job runs on a feature branch; executor scoped to specific projects; spec copied from another project; executor requires a docker image field the job doesn't set; runners unregistered so capacity criteria fail.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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

Appendix: source

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

				return false;
			}
		} else {
			return executor.isApplicable(new JobMatchContext(
					build.getProject(), null, build.getCommitId(),
					build.getJobName()));
		}
	}

	private JobExecutor getJobExecutor(Build build, @Nullable String jobExecutorName, TaskLogger jobLogger) {
		if (jobExecutorName != null) {
			var jobExecutor = settingService.getJobExecutors().stream()
				.filter(it -> it.getName().equals(jobExecutorName))
				.findFirst()
				.orElseThrow(() -> new ExplicitException("Unable to find specified job executor '" + jobExecutorName + "'"));
			if (!jobExecutor.isEnabled())
				throw new ExplicitException("Specified job executor '" + jobExecutorName + "' is disabled");
			else if (!isApplicable(build, jobExecutor))
				throw new ExplicitException("Specified job executor '" + jobExecutorName + "' is not applicable for current job");
			else 
				return jobExecutor;
		} else {
			if (!settingService.getJobExecutors().isEmpty()) {
				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());

View on GitHub (pinned to d44925c47c)