theonedev/onedev · error · ExplicitException

Group ' ' is included multiple times

Error message

Group '${groupName}' is included multiple times

What it means

While parsing a review requirement, each 'group:<name>' criterion is resolved and stored in a map keyed by group; if the same group appears twice ExplicitException is thrown because the required approver count for that group would be ambiguous.

Solutions

  1. Deduplicate the group in the requirement string
  2. Merge duplicate group clauses into one clause with the required count, e.g. 'group:qa with 2 approvals'
  3. Catch ExplicitException on save and validate requirement strings programmatically

Example fix

// before
reviewRequirement = "group:qa or group:qa";
// after
reviewRequirement = "group:qa";
Defensive patterns

Strategy: validation

Validate before calling

java.util.Set<String> seen = new java.util.HashSet<>();
for (String name : extractGroupNames(requirement)) {
    if (!seen.add(name))
        throw new ExplicitException("Duplicate group in requirement: " + name);
}

Try / catch

try {
    ReviewRequirement.parse(req);
} catch (ExplicitException e) {
    ui.showError(e.getMessage());
}

Prevention

When it happens

Trigger: Parsing a requirement string with the same group in multiple criteria, e.g. 'group:qa or group:qa', including duplicates arising from combined and/or branches.

Common situations: Requirements assembled by merging branch policies; template-generated strings that append clauses without checking existing groups.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

Thrown at server-core/src/main/java/io/onedev/server/util/reviewrequirement/ReviewRequirement.java:77

						if (!users.contains(user)) 
							users.add(user);
						else 
							throw new ExplicitException("User '" + userName + "' is included multiple times");
					} else {
						throw new ExplicitException("Unable to find user '" + userName + "'");
					}
				} else if (criteria.groupCriteria() != null) {
					String groupName = getValue(criteria.groupCriteria().Value());
					Group group = OneDev.getInstance(GroupService.class).find(groupName);
					if (group != null) {
						if (!groups.containsKey(group)) {
							TerminalNode digit = criteria.groupCriteria().DIGIT();
							if (digit != null) 
								groups.put(group, Integer.parseInt(digit.getText()));
							else 
								groups.put(group, 1);
						} else {
							throw new ExplicitException("Group '" + groupName + "' is included multiple times");
						}
					} else {
						throw new ExplicitException("Unable to find group '" + groupName + "'");
					}
				}
			}			
		}
		
		return new ReviewRequirement(users, groups);
	}

	private static String getValue(TerminalNode terminal) {
		return StringUtils.unescape(FenceAware.unfence(terminal.getText())).trim();
	}
	
	public List<User> getUsers() {
		return users;
	}

View on GitHub (pinned to d44925c47c)