theonedev/onedev · error · ValidationException
Specified issues already linked via specified link spec
Error message
Specified issues already linked via specified link spec
What it means
In the branch where the spec has no opposite (unidirectional link spec), validate() first rejects exact duplicates: if the source issue's links already contain a link of the same spec pointing at the same target, creating it again would be redundant, so this ValidationException is thrown.
Source
Thrown at server-core/src/main/java/io/onedev/server/model/IssueLink.java:108
.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
- Skip creating the link if it already exists — check getLinks() for the spec/target pair first.
- Make import/automation scripts idempotent by looking up the existing IssueLink before insertion.
- Catch ValidationException and treat 'already linked' as success in retry logic.
Example fix
// before IssueLink.createLink(link); // after boolean exists = src.getLinks().stream().anyMatch(l -> l.getSpec().equals(spec) && l.getLinked(src).equals(tgt)); if (!exists) IssueLink.createLink(link);
Defensive patterns
Strategy: validation
Validate before calling
boolean exists = source.getLinks().stream().anyMatch(l -> l.getSpec().equals(spec) && l.getLinked(source).equals(target)); if (exists) return; // already linked, nothing to do
Try / catch
try { IssueLink.createLink(link); } catch (ValidationException e) { if (e.getMessage().contains("already linked")) { /* treat as success */ } else { throw e; } } Prevention
- Always check for an existing link before creating
- Use idempotent create-or-get logic in scripts and REST calls
- Debounce/duplicate-protect the link button in custom UIs
When it happens
Trigger: createLink called where getSpec().getOpposite() == null and getSource().getLinks() already has a link with equal spec whose getLinked(source) equals the requested target.
Common situations: User double-clicks the 'link issue' button; a REST script retries a failed request that actually succeeded (no idempotency); bulk import runs twice over the same data.
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
- No permission to add specified link for specified issues
- Duplicate dependency build '" + dependencyBuild.getReference
- 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 is not multiple and the target is
AI-assisted analysis of theonedev/onedev@d44925c47c (2026-09-06).
Data as JSON: /api/errors/c6e4d267fc3541d7.
Report an issue: GitHub.