theonedev/onedev · error · ExplicitException

User ' ' 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.

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.

Appendix: 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)