theonedev/onedev · error · ValidationException
Circular dependencies (
Error message
Circular dependencies (
What it means
BuildSpec.checkDependencies validates job dependency graphs and throws ValidationException 'Circular dependencies ([...])' when following JobDependency links returns to a job already in the dependency chain. This prevents unbuildable job graphs where jobs wait on each other forever.
Source
Thrown at server-core/src/main/java/io/onedev/server/buildspec/BuildSpec.java:526
throw new ValidationException(String.format("Error validating step template parameters (%s)", e.getMessage()));
}
}
templateChain.add(step.getTemplateName());
for (Step templateStep: template.getSteps()) {
if (templateStep instanceof UseTemplateStep)
checkTemplateUsages((UseTemplateStep) templateStep, new ArrayList<>(templateChain));
}
} else if (templateChain.isEmpty()) {
throw new ValidationException("Step template not found (" + step.getTemplateName() + ")");
}
}
}
private void checkDependencies(Job job, List<String> dependencyChain) {
for (JobDependency dependency: job.getJobDependencies()) {
if (dependencyChain.contains(dependency.getJobName())) {
dependencyChain.add(dependency.getJobName());
throw new ValidationException("Circular dependencies (" + dependencyChain + ")");
} else {
Job dependencyJob = getJobMap().get(dependency.getJobName());
if (dependencyJob != null) {
if (dependencyChain.isEmpty()) {
try {
ParamUtils.validateParamMatrix(dependencyJob.getParamSpecs(), dependency.getParamMatrix());
for (var paramMap: dependency.getExcludeParamMaps())
ParamUtils.validateParamMap(dependencyJob.getParamSpecs(), paramMap.getParams());
} catch (ValidationException e) {
String message = String.format("Error validating dependency job parameters (dependency job: %s, error message: %s)",
dependencyJob.getName(), e.getMessage());
throw new ValidationException(message);
}
}
List<String> newDependencyChain = new ArrayList<>(dependencyChain);
newDependencyChain.add(dependency.getJobName());
checkDependencies(dependencyJob, newDependencyChain);
} else if (dependencyChain.isEmpty()) {View on GitHub (pinned to d44925c47c)
Solutions
- Break the cycle shown in the message chain by removing one jobDependencies entry
- If both jobs genuinely need each other's outputs, merge them into one job or use artifacts/parallel setup instead of dependencies
- Review the dependency graph in the build spec editor to visualize cycles before saving
Example fix
# before: cycle a <-> b
- name: a
jobDependencies: [{jobName: b}]
- name: b
jobDependencies: [{jobName: a}]
# after
- name: a
jobDependencies: []
- name: b
jobDependencies: [{jobName: a}] Defensive patterns
Strategy: validation
Validate before calling
// topological sort of jobDependencies; if sort fails, a cycle exists
Try / catch
try {
buildSpec.isValid();
} catch (ValidationException e) {
// 'Circular dependencies ([a, b, ...])': remove one edge from the listed cycle
} Prevention
- Keep job dependencies forming a DAG
- Sketch the dependency graph before adding cross-job links
- Never create mutual dependencies between two jobs
- Use the editor's dependency visualization
When it happens
Trigger: Job A depends on job B and job B (directly or transitively) depends on job A; checked when isValid() validates the spec containing such jobDependencies.
Common situations: Adding a dependency to speed up ordering but creating a cycle accidentally; two teams each making their job depend on the other's; copying dependency blocks between jobs without removing the reverse link.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- Dependency job not found (
- Error validating dependency job parameters (dependency job:
- Circular template usages (
- Error validating step template parameters (%s)
- Step template not found (
AI-assisted analysis of theonedev/onedev@d44925c47c (2026-09-06).
Data as JSON: /api/errors/6e20fb9aed0bc6fb.
Report an issue: GitHub.