{"record":{"id":"b6f9c7f2e114aa2c","repo":"theonedev/onedev","slug":"can-only-compare-with-common-ancestor-when-differe","errorCode":null,"errorMessage":"Can only compare with common ancestor when different projects are involved","messagePattern":"Can only compare with common ancestor when different projects are involved","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"server-core/src/main/java/io/onedev/server/web/page/project/compare/RevisionComparePage.java","lineNumber":246,"sourceCode":"\t\telse if (defaultRevision != null) \n\t\t\tstate.rightSide = new ProjectAndRevision(getProject(), defaultRevision);\n\t\telse\n\t\t\tstate.rightSide = new ProjectAndRevision(getProject(), null);\n\t\t\n\t\tif (state.rightSide.getRevision() != null)\n\t\t\trightCommitId = state.rightSide.getCommit().copy();\n\t\t\n\t\tstate.compareWithMergeBase = params.get(PARAM_COMPARE_WITH_MERGE_BASE).toBoolean(true);\n\t\t\n\t\t/*\n\t\t * When compare across different projects, left revision and right revision might not \n\t\t * exist in same project and this cause many difficulties such as calculating changes, \n\t\t * recording comment revisions, or get permanent mark urls. So we add below constraint as\n\t\t * merge base commit and right side revision are guaranteed to be both in right side \n\t\t * project  \n\t\t */\n\t\tif (!state.compareWithMergeBase && !state.leftSide.getProject().equals(state.rightSide.getProject())) \n\t\t\tthrow new IllegalArgumentException(_T(\"Can only compare with common ancestor when different projects are involved\"));\n\t\t\n\t\tstate.pathFilter = params.get(PARAM_PATH_FILTER).toString();\n\t\tstate.blameFile = params.get(PARAM_BLAME_FILE).toString();\n\t\tstate.whitespaceOption = WhitespaceOption.ofName(\n\t\t\t\tparams.get(PARAM_WHITESPACE_OPTION).toString(WhitespaceOption.IGNORE_TRAILING.name()));\n\t\t\n\t\tstate.commitQuery = params.get(PARAM_COMMIT_QUERY).toString();\n\t\t\n\t\tstate.commentId = params.get(PARAM_COMMENT).toOptionalLong();\n\t\tstate.mark = Mark.fromString(params.get(PARAM_MARK).toString());\n\t\t\n\t\tstate.tabPanel = TabPanel.of(params.get(PARAM_TAB).toString());\n\t\t\n\t\trequestModel = new LoadableDetachableModel<PullRequest>() {\n\n\t\t\t@Override\n\t\t\tprotected PullRequest load() {\n\t\t\t\tif (state.leftSide.getBranch() != null && state.rightSide.getBranch() != null) {","sourceCodeStart":228,"sourceCodeEnd":264,"githubUrl":"https://github.com/theonedev/onedev/blob/d44925c47c37992c828ea673a5f9620539bc3ff2/server-core/src/main/java/io/onedev/server/web/page/project/compare/RevisionComparePage.java#L228-L264","documentation":"RevisionComparePage enforces an invariant on its compare state: when the comparison is not against the merge base, the left and right sides must belong to the same project; conversely, merge-base comparison is the only mode allowed when projects differ. Violating this while parsing URL parameters throws IllegalArgumentException with this message.","triggerScenarios":"Building a compare URL (PARAM_COMPARE_WITH_MERGE_BASE absent/false) where the left-side and right-side revisions resolve to different projects, e.g. manually crafted cross-project compare links without the merge-base flag.","commonSituations":"Constructing cross-project comparison URLs by hand or via scripts; bookmarks saved before a compare-layout change; copying a same-project compare link and swapping only the project of one side.","solutions":["Add/enable the merge-base comparison parameter in the URL when comparing across projects.","Or restrict the comparison to two revisions within the same project.","If generated programmatically, use RevisionComparePage.paramsOf / CompareParams helpers instead of hand-building the URL so flags stay consistent."],"exampleFix":"// before\nString url = \"/~compare?query=a@projectA...b@projectB\"; // no merge-base flag\n// after\nString url = \"/~compare?query=a@projectA...b@projectB&compareWithMergeBase=true\";","handlingStrategy":"validation","validationCode":"boolean sameProject = leftProject.equals(rightProject);\nboolean mergeBase = params.containsKey(\"compareWithMergeBase\") && params.getBoolean(\"compareWithMergeBase\");\nif (!sameProject && !mergeBase) throw new IllegalArgumentException(\"Cross-project compare requires merge-base mode\");","typeGuard":null,"tryCatchPattern":"try {\n    // open compare page\n} catch (IllegalArgumentException e) {\n    // rebuild URL with compareWithMergeBase=true\n}","preventionTips":["Use paramsOf/CompareParams helpers to build compare URLs.","Always enable merge-base comparison for cross-project compares.","Validate left/right project equality before generating links."],"tags":["onedev","git","compare","invalid-argument"],"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-14T05:17:10.506Z"}