theonedev/onedev · error · ExplicitException

No job context found for specified job token

Error message

No job context found for specified job token

What it means

Thrown by DefaultJobService.getJobContext(jobToken, mustExist=true) when the given job token has no entry in the jobServers map — no build on this server (or cluster member) was ever assigned that token. OneDev keys running job contexts by the UUID token generated at submission time, so an unknown token means the caller's credentials/context don't correspond to any live job.

Source

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

	}

	private void log(Throwable e, TaskLogger logger) {
		if (find(e, TimeoutException.class) != null) {
			logger.error(TIMEOUT_MESSAGE);
		} else {
			var explicitException = find(e, ExplicitException.class);
			if (explicitException != null)
				logger.error(explicitException.getMessage());
			else
				logger.error("Error executing job", e);
		}
	}

	@Override
	public JobContext getJobContext(String jobToken, boolean mustExist) {
		var jobServer = jobServers.get(jobToken);
		if (mustExist && jobServer == null)
			throw new ExplicitException("No job context found for specified job token");
		if (jobServer != null) {
			var jobContext = clusterService.runOnServer(jobServer, () -> jobContexts.get(jobToken));
			if (mustExist && jobContext == null)
				throw new ExplicitException("No job context found for specified job token");
			return jobContext;
		} else {
			return null;
		}
	}

	private void markBuildError(Build build, String errorMessage) {
		build.setStatus(Build.Status.FAILED);
		logService.newLogger(build.getLoggingSupport()).error(errorMessage);
		build.setFinishDate(new Date());
		buildService.update(build);
		listenerRegistry.post(new BuildFinished(build));
	}

View on GitHub (pinned to d44925c47c)

Solutions

  1. Use the job token assigned to the currently running build (build.getToken()), e.g. via the job's token placeholder in scripts.
  2. Verify the runner is talking to the same OneDev instance that submitted the job.
  3. Re-submit the job if the server was restarted — old tokens are not recoverable.
  4. Pass mustExist=false if you only want to probe for context existence and handle null.

Example fix

// before
JobContext ctx = jobService.getJobContext(staleToken, true);

// after: read the live token from the build context
JobContext ctx = jobService.getJobContext(build.getToken(), true);
if (ctx == null) { /* handle finished/unknown job */ }
Defensive patterns

Strategy: try-catch

Validate before calling

// Only pass tokens obtained from build.getToken() of a live build on this instance
String token = build.getToken();
if (token == null || token.isEmpty()) {
    throw new IllegalStateException("Build has no job token (not yet submitted?)");
}

Try / catch

try {
    JobContext ctx = jobService.getJobContext(token, true);
} catch (ExplicitException e) {
    if (e.getMessage().contains("No job context found")) {
        // re-fetch build status from DB/API; token is stale or unknown
    }
}

Prevention

When it happens

Trigger: An agent or script calls getJobContext with a stale, mistyped, or never-issued job token while mustExist=true; server restarted and jobServers map lost; job finished and its token was removed; token from a different OneDev instance.

Common situations: Custom agent scripts caching an old job token; restarting the server mid-job; pointing a runner at the wrong OneDev server; copying tokens between environments; job already completed and cleaned up.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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