theonedev/onedev · error · ValidationException
Cannot link to self
Error message
Cannot link to self
What it means
Domain validation in IssueLink.validate: source and target issues are the same issue, which a self-link cannot represent (getLinked would be ambiguous); ValidationException is raised. Called from createLink, so the invalid link is rejected before persistence. Fix: link two distinct issues.
Source
Thrown at server-core/src/main/java/io/onedev/server/model/IssueLink.java:87
public void setSpec(LinkSpec spec) {
this.spec = spec;
}
public Issue getLinked(Issue issue) {
return issue.equals(source)?target:source;
}
public int getPosition() {
return position;
}
public void setPosition(int position) {
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 {View on GitHub (pinned to d44925c47c)
Solutions
- Ensure the target issue id differs from the source issue id before calling createLink
- Guard scripts: skip linking when source.getId() == target.getId()
- Fix import/bulk data so self-references are removed
Example fix
// before issueLinkService.createLink(issue, issue, spec); // self link // after if (!target.equals(issue)) issueLinkService.createLink(issue, target, spec);
Defensive patterns
Strategy: validation
Validate before calling
if (source.equals(target)) { /* skip or reject link */ } Try / catch
try { issueLinkService.createLink(source, target, spec); } catch (ValidationException e) { log.warn("Link rejected: " + e.getMessage()); } Prevention
- Guard against self-links in scripts and imports
- Validate source != target before any createLink call
- Test automation with edge-case issue ids
When it happens
Trigger: Creating an issue link (via UI, API, or createLink) where source issue equals target issue, e.g. passing the same issue id for both ends.
Common situations: Automation scripts computing the link target incorrectly (off-by-one/wrong variable); UI bugs allowing self-selection; bulk import scripts linking an issue to itself; copy-paste of issue numbers.
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
- Source issue already linked to target issue via specified li
- Title is required
- Issue ${issueReference} is not in current project
- Invalid issue id/number
- Not eligible for multi-value
AI-assisted analysis of theonedev/onedev@d44925c47c (2026-09-06).
Data as JSON: /api/errors/70e7a317688304ba.
Report an issue: GitHub.