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

  1. Open the step templates definition in the build spec and remove the UseTemplateStep that closes the cycle shown in the message's chain
  2. Unfold one level of the cycle by inlining the needed steps instead of reusing the template
  3. Rename templates after refactoring and re-check all UseTemplateStep references
  4. 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

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


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