theonedev/onedev · error · ValidationException
Circular template usages (
Error message
Circular template usages (
What it means
During build spec validation, BuildSpec.checkTemplateUsages walks UseTemplateStep references and maintains a template chain. When a step template indirectly includes itself (directly or through other templates), a ValidationException 'Circular template usages ([...])' is thrown listing the chain. This prevents infinite template expansion at build time.
Source
Thrown at server-core/src/main/java/io/onedev/server/buildspec/BuildSpec.java:498
.addBeanNode()
.inIterable().atIndex(importIndex)
.addConstraintViolation();
}
isValid = false;
}
}
}
}
if (!isValid)
context.disableDefaultConstraintViolation();
return isValid;
}
private void checkTemplateUsages(UseTemplateStep step, List<String> templateChain) {
if(templateChain.contains(step.getTemplateName())) {
templateChain.add(step.getTemplateName());
throw new ValidationException("Circular template usages (" + templateChain + ")");
} else {
StepTemplate template = getStepTemplateMap().get(step.getTemplateName());
if (template != null) {
if (templateChain.isEmpty()) {
try {
ParamUtils.validateParamMatrix(template.getParamSpecs(), step.getParamMatrix());
for (var paramMap: step.getExcludeParamMaps())
ParamUtils.validateParamMap(template.getParamSpecs(), paramMap.getParams());
} catch (Exception e) {
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()) {View on GitHub (pinned to d44925c47c)
Solutions
- Open the step templates definition in the build spec and remove the UseTemplateStep that closes the cycle shown in the message's chain
- Unfold one level of the cycle by inlining the needed steps instead of reusing the template
- Rename templates after refactoring and re-check all UseTemplateStep references
- Test template definitions in the build spec editor, which validates templates before save
Example fix
# before: template 'deploy' includes itself
- name: deploy
steps:
- !UseTemplateStep
templateName: deploy
# after
- name: deploy
steps:
- !RunCommandStep
commands: ./deploy.sh Defensive patterns
Strategy: validation
Validate before calling
// ensure no template includes itself, directly or transitively: // for each UseTemplateStep in stepTemplates, resolve templateName; // fail if a name repeats while following the chain
Try / catch
try {
buildSpec.isValid();
} catch (ValidationException e) {
// e.getMessage() lists the circular chain; remove the offending UseTemplateStep
} Prevention
- Never let a template reference itself, even indirectly
- After renaming templates, grep all UseTemplateStep references
- Keep shared-step templates acyclic and documented
- Validate specs in the editor before committing
When it happens
Trigger: Defining step template A whose steps include a UseTemplateStep referencing template A, or templates A->B->A; occurs when isValid() is called on a build spec containing such templates.
Common situations: Copy-pasting template steps so a template accidentally references itself; renaming templates and leaving a stale self-reference; refactoring common steps into a shared template that both templates include.
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
- Error validating step template parameters (%s)
- Step template not found (
- Circular dependencies (
- Dependency job not found (
- Error validating imported build spec (import project: %s, im
AI-assisted analysis of theonedev/onedev@d44925c47c (2026-09-06).
Data as JSON: /api/errors/d5073f30f2626b03.
Report an issue: GitHub.