theonedev/onedev · error · ExplicitException

User '${userName}' is included multiple times

Error message

User '${userName}' is included multiple times

What it means

While parsing a review requirement, each 'user:<name>' criterion is resolved via UserService.findByName and accumulated into a set; a duplicate user throws ExplicitException with this message. The requirement would count the same user twice, which is ambiguous, so it is rejected up front.

Source

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

				}
				
			});
			CommonTokenStream tokens = new CommonTokenStream(lexer);
			ReviewRequirementParser parser = new ReviewRequirementParser(tokens);
			parser.removeErrorListeners();
			parser.setErrorHandler(new BailErrorStrategy());
			
			RequirementContext requirementContext = parser.requirement();
			
			for (CriteriaContext criteria: requirementContext.criteria()) {
				if (criteria.userCriteria() != null) {
					String userName = getValue(criteria.userCriteria().Value());
					User user = OneDev.getInstance(UserService.class).findByName(userName);
					if (user != null) {
						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 + "'");

View on GitHub (pinned to d44925c47c)

Solutions

  1. Remove the duplicate user occurrence from the requirement string
  2. Replace the duplicated user with a group covering both occurrences
  3. Wrap parse in try-catch on ExplicitException and show a user-friendly message

Example fix

// before
reviewRequirement = "user:bob or user:bob";
// after
reviewRequirement = "user:bob";
Defensive patterns

Strategy: validation

Validate before calling

java.util.Set<String> seen = new java.util.HashSet<>();
for (String name : extractUserNames(requirement)) {
    if (!seen.add(name))
        throw new ExplicitException("Duplicate user 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 listing the same user twice, e.g. 'user:bob or user:bob', or a user appearing in multiple criteria branches of the same expression.

Common situations: Hand-maintained requirement strings that grew over time; copy-paste of a branch that duplicated a name; automation generating requirements without deduplication.

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/1492bd7e43b61eb2. Report an issue: GitHub.