{"record":{"id":"1d0ef0f9dad65f4c","repo":"theonedev/onedev","slug":"opposite-side-of-link-spec-not-allowed-to-link-to","errorCode":null,"errorMessage":"Opposite side of link spec not allowed to link to the source issue","messagePattern":"Opposite side of link spec not allowed to link to the source issue","errorType":"validation","errorClass":"ValidationException","httpStatus":null,"severity":"error","filePath":"server-core/src/main/java/io/onedev/server/model/IssueLink.java","lineNumber":104,"sourceCode":"\t\tif (getSource().equals(getTarget()))\n\t\t\tthrow new ValidationException(\"Cannot link to self\");\n\t\tif (getSpec().getOpposite() != null) {\n\t\t\tif (getSource().getTargetLinks().stream()\n\t\t\t\t\t.anyMatch(it -> it.getSpec().equals(getSpec()) && it.getTarget().equals(getTarget())))\n\t\t\t\tthrow new ValidationException(\"Source issue already linked to target issue via specified link spec\");\n\t\t\tif (!getSpec().isMultiple()\n\t\t\t\t\t&& getSource().getTargetLinks().stream().anyMatch(it -> it.getSpec().equals(getSpec())))\n\t\t\t\tthrow new ValidationException(\n\t\t\t\t\t\t\"Link spec is not multiple and the source issue is already linked to another issue via this link spec\");\n\t\t\tif (!getSpec().getParsedIssueQuery(getSource().getProject()).matches(getTarget()))\n\t\t\t\tthrow new ValidationException(\"Link spec not allowed to link to the target issue\");\n\t\t\tif (!getSpec().getOpposite().isMultiple()\n\t\t\t\t\t&& getTarget().getSourceLinks().stream().anyMatch(it -> it.getSpec().equals(getSpec())))\n\t\t\t\tthrow new ValidationException(\n\t\t\t\t\t\t\"Opposite side of link spec is not multiple and the target issue is already linked to another issue via this link spec\");\n\t\t\tif (!getSpec().getOpposite().getParsedIssueQuery(getSource().getProject())\n\t\t\t\t\t.matches(getSource()))\n\t\t\t\tthrow new ValidationException(\"Opposite side of link spec not allowed to link to the source issue\");\n\t\t} else {\n\t\t\tif (getSource().getLinks().stream().anyMatch(it -> it.getSpec().equals(getSpec())\n\t\t\t\t\t&& it.getLinked(getSource()).equals(getTarget())))\n\t\t\t\tthrow new ValidationException(\"Specified issues already linked via specified link spec\");\n\t\t\tif (!getSpec().isMultiple()\n\t\t\t\t\t&& getSource().getLinks().stream().anyMatch(it -> it.getSpec().equals(getSpec())))\n\t\t\t\tthrow new ValidationException(\n\t\t\t\t\t\t\"Link spec is not multiple and source issue is already linked to another issue via this link spec\");\n\t\t\tvar parsedIssueQuery = getSpec().getParsedIssueQuery(getSource().getProject());\n\t\t\tif (!parsedIssueQuery.matches(getSource()) || !parsedIssueQuery.matches(getTarget()))\n\t\t\t\tthrow new ValidationException(\"Link spec not allowed to link specified issues\");\n\t\t}\n\t}\n}\n","sourceCodeStart":86,"sourceCodeEnd":119,"githubUrl":"https://github.com/theonedev/onedev/blob/d44925c47c37992c828ea673a5f9620539bc3ff2/server-core/src/main/java/io/onedev/server/model/IssueLink.java#L86-L119","documentation":"For a bidirectional spec, validate() checks the source issue against the OPPOSITE spec's issue query as well. This error is thrown when the source issue fails getSpec().getOpposite().getParsedIssueQuery(...) evaluated in the source project — the spec disallows the source side of the link.","triggerScenarios":"createLink where getSpec().getOpposite() defines an issue query and getSource() does not match it.","commonSituations":"Opposite query restricts linking by state (e.g. only open issues can be linked) and the source issue is closed; the source issue is of a type excluded by the opposite query; query was changed between drafting and saving the link.","solutions":["Make sure the source issue satisfies the opposite spec's issue query (change its state/type if appropriate).","Relax the opposite spec's issue query in Administration > Links.","Use a different, less restrictive link spec."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"var oppositeQuery = link.getSpec().getOpposite().getParsedIssueQuery(link.getSource().getProject());\nif (!oppositeQuery.matches(link.getSource())) throw new IllegalStateException(\"source not allowed by opposite query\");","typeGuard":null,"tryCatchPattern":"try { IssueLink.createLink(link); } catch (ValidationException e) { // inform user the source issue violates the opposite spec query }","preventionTips":["Validate the source issue state/type against the opposite query before linking","Keep opposite-side queries aligned with the primary side","Update issue state before linking when queries filter on state"],"tags":["issue-links","issue-query","validation"],"backgroundTag":"invalid-argument-value","analyzedSha":"d44925c47c37992c828ea673a5f9620539bc3ff2","analyzedAt":"2026-09-06T07:18:27.995Z","contentChangedAt":"2026-09-06T07:18:27.995Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}