theonedev/onedev · error · ValidationException
Opposite side of link spec is not multiple and the target is
Error message
Opposite side of link spec is not multiple and the target issue is already linked to another issue via this link spec
What it means
For a bidirectional link spec, validate() also enforces the OPPOSITE side's multiplicity: if the opposite spec isMultiple() is false, the target issue may have at most one link of this spec on its source side. This is thrown when the target already has a source link with the same spec pointing at another issue.
Source
Thrown at server-core/src/main/java/io/onedev/server/model/IssueLink.java:100
this.position = position;
}
public void validate() {
if (getSource().equals(getTarget()))
throw new ValidationException("Cannot link to self");
if (getSpec().getOpposite() != null) {
if (getSource().getTargetLinks().stream()
.anyMatch(it -> it.getSpec().equals(getSpec()) && it.getTarget().equals(getTarget())))
throw new ValidationException("Source issue already linked to target issue via specified link spec");
if (!getSpec().isMultiple()
&& getSource().getTargetLinks().stream().anyMatch(it -> it.getSpec().equals(getSpec())))
throw new ValidationException(
"Link spec is not multiple and the source issue is already linked to another issue via this link spec");
if (!getSpec().getParsedIssueQuery(getSource().getProject()).matches(getTarget()))
throw new ValidationException("Link spec not allowed to link to the target issue");
if (!getSpec().getOpposite().isMultiple()
&& getTarget().getSourceLinks().stream().anyMatch(it -> it.getSpec().equals(getSpec())))
throw new ValidationException(
"Opposite side of link spec is not multiple and the target issue is already linked to another issue via this link spec");
if (!getSpec().getOpposite().getParsedIssueQuery(getSource().getProject())
.matches(getSource()))
throw new ValidationException("Opposite side of link spec not allowed to link to the source issue");
} else {
if (getSource().getLinks().stream().anyMatch(it -> it.getSpec().equals(getSpec())
&& it.getLinked(getSource()).equals(getTarget())))
throw new ValidationException("Specified issues already linked via specified link spec");
if (!getSpec().isMultiple()
&& getSource().getLinks().stream().anyMatch(it -> it.getSpec().equals(getSpec())))
throw new ValidationException(
"Link spec is not multiple and source issue is already linked to another issue via this link spec");
var parsedIssueQuery = getSpec().getParsedIssueQuery(getSource().getProject());
if (!parsedIssueQuery.matches(getSource()) || !parsedIssueQuery.matches(getTarget()))
throw new ValidationException("Link spec not allowed to link specified issues");
}
}
}View on GitHub (pinned to d44925c47c)
Solutions
- Remove the target's existing link of this spec before creating the new one.
- Enable 'Multiple' on the opposite side of the link spec in project link settings.
- Choose a target issue that currently has no link of this spec.
Example fix
// before IssueLink.createLink(link); // target already linked elsewhere via opposite spec // after IssueLink conflicting = tgt.getSourceLinks().stream().filter(l -> l.getSpec().equals(spec)).findFirst().orElse(null); if (conflicting != null) conflicting.remove(); IssueLink.createLink(link);
Defensive patterns
Strategy: validation
Validate before calling
boolean targetFree = link.getSpec().getOpposite().isMultiple() || link.getTarget().getSourceLinks().stream().noneMatch(l -> l.getSpec().equals(link.getSpec()));
if (!targetFree) { /* pick another target or unlink */ } Try / catch
try { IssueLink.createLink(link); } catch (ValidationException e) { // unlink target's existing link of the spec, then retry } Prevention
- Check both endpoints' existing links before creating a link
- Enable Multiple on both sides for many-to-many semantics
- Make link automation idempotent and pre-clean conflicts
When it happens
Trigger: createLink called where getSpec().getOpposite().isMultiple() == false and getTarget().getSourceLinks() already contains a link with an equal spec whose target-side owner (linked source) differs from the requested source issue.
Common situations: Symmetric case of error 340 on the target end: trying to make a target be 'blocks' for two issues while the opposite side is single-capacity; specs toggled to non-multiple after data was created; batch importers linking one issue as parent of several children when the spec only allows one.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Link spec is not multiple and source issue is already linked
- Link spec is not multiple and the source issue is already li
- Link spec not allowed to link to the target issue
- Opposite side of link spec not allowed to link to the source
- Link spec not allowed to link specified issues
AI-assisted analysis of theonedev/onedev@d44925c47c (2026-09-06).
Data as JSON: /api/errors/ab47003cd7c24ce8.
Report an issue: GitHub.