theonedev/onedev · error · ExplicitException

Build spec not defined (project: %s, commit: %s)

Error message

Build spec not defined (project: %s, commit: %s)

What it means

DefaultJobService.submit resolves the build spec (.onedev-buildspec) from the given project and commit. If the commit has no build spec defined (project.getBuildSpec(commitId) returns null), no job can run, and an ExplicitException is thrown naming the project and commit. This guard runs inside the uniqueness lock before validation and submission.

Source

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

		}
	}

	@Transactional
	@Override
	public Build submit(User user, Project project, ObjectId commitId, String jobName, 
						Map<String, List<String>> paramMap, String refName, 
						PullRequest request, Issue issue, String reason) {
		Lock lock = LockUtils.getLock("job-manager: " + project.getId() + "-" + commitId.name());
		transactionService.mustRunAfterTransaction(() -> lock.unlock());

		JobAuthorizationContext.push(new JobAuthorizationContext(project, commitId, request));
		try {
			// Lock to guarantee uniqueness of build (by project, commit, job and parameters)
			lock.lockInterruptibly();

			BuildSpec buildSpec = project.getBuildSpec(commitId);
			if (buildSpec == null) {
				throw new ExplicitException(String.format(
						"Build spec not defined (project: %s, commit: %s)",
						project.getPath(), commitId.name()));
			}

			validateBuildSpec(project, commitId, buildSpec);

			if (!buildSpec.getJobMap().containsKey(jobName)) {
				var errorMessage = String.format(
						"Job not found (project: %s, commit: %s, job: %s)",
						project.getPath(), commitId.name(), jobName);
				throw new BadRequestException(errorMessage);
			}

			return doSubmit(user, project, commitId, jobName, paramMap, refName, request, issue, reason);
		} catch (Throwable t) {
			throw ExceptionUtils.unchecked(t);
		} finally {
			JobAuthorizationContext.pop();

View on GitHub (pinned to d44925c47c)

Solutions

  1. Add a valid .onedev-buildspec to the repository and commit it on the target branch.
  2. Verify the commitId/refName you submit against actually contains the build spec (browse the commit in the UI).
  3. If using branch schedules/webhook triggers, restrict them to branches known to have the spec.

Example fix

// before
git.push(...); jobService.submit(user, project, commitId, "build", ...); // spec not on branch yet
// after
commitBuildSpecToBranch("main"); // add .onedev-buildspec
ObjectId c = project.getRevision("main").getCommitId();
if (project.getBuildSpec(c) != null) jobService.submit(user, project, c, "build", ...);
Defensive patterns

Strategy: validation

Validate before calling

if (project.getBuildSpec(commitId) == null)
  throw new ExplicitException("No .onedev-buildspec at " + commitId.name() + "; add one before triggering CI");

Try / catch

try { jobService.submit(...); } catch (ExplicitException e) { if (e.getMessage().startsWith("Build spec not defined")) notifyMissingSpec(project, commitId); throw e; }

Prevention

When it happens

Trigger: Calling jobService.submit (directly or via run/build) with a commit that lacks a .onedev-buildspec file, or where the file is empty/not recognized as a build spec at that revision.

Common situations: Triggering CI on a branch that never added .onedev-buildspec; pushing to a commit before the build spec was committed; wrong refName/commit passed so the lookup hits a pre-spec history; spec file named or located incorrectly.

Understand the failure class

Background: "X is required", "must be set", "cannot be empty": the missing-required-config error family, from Vertex AI project/location to WeChat keys — this error's family across 18 libraries.

Related errors


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