{"record":{"id":"1212a3c93730afb7","repo":"alibaba/open-code-review","slug":"resume-rejected-repository-identity-changed-so-t","errorCode":null,"errorMessage":"resume rejected: repository identity changed, so this is not the repository the parent run reviewed; %s","messagePattern":"resume rejected: repository identity changed, so this is not the repository the parent run reviewed; (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/session/resume_identity.go","lineNumber":114,"sourceCode":"\tcase m.SchemaVersion != ManifestSchemaVersion:\n\t\treturn fmt.Errorf(\"resume session %q carries manifest schema %q, but this build can only verify %q; %s\", s.SessionID, m.SchemaVersion, ManifestSchemaVersion, resumeHint)\n\tcase m.Operation != OperationReview:\n\t\treturn fmt.Errorf(\"resume session %q recorded operation %q, not %q; %s\", s.SessionID, m.Operation, OperationReview, resumeHint)\n\tcase len(m.Coverage.Selected) == 0:\n\t\t// Without this, an empty parent and an empty child would both hash to the\n\t\t// canonical empty digest, pass every comparison, and produce a run that\n\t\t// reuses nothing and dispatches nothing.\n\t\treturn fmt.Errorf(\"resume session %q selected no input, so it has nothing to resume; %s\", s.SessionID, resumeHint)\n\t}\n\n\tif m.Input.Mode != id.Mode {\n\t\t// Mode feeds item_id derivation, so parent and child items cannot even be\n\t\t// put side by side.\n\t\treturn fmt.Errorf(\"resume rejected: input mode changed from %q to %q; %s\", m.Input.Mode, id.Mode, resumeHint)\n\t}\n\t// Both sides empty means a repository with no remote, which is unchanged.\n\tif m.Repository.IdentitySHA256 != id.RepositorySHA256 {\n\t\treturn fmt.Errorf(\"resume rejected: repository identity changed, so this is not the repository the parent run reviewed; %s\", resumeHint)\n\t}\n\tif m.Input.SourceArtifactSHA256 != id.SourceArtifactSHA256 {\n\t\treturn fmt.Errorf(\"resume rejected: the reviewed input changed since session %q — a ref may now point at a different commit, or the selected file set changed; %s\", s.SessionID, resumeHint)\n\t}\n\tif m.Execution.RuleConfigSHA256 == \"\" {\n\t\treturn fmt.Errorf(\"resume session %q recorded no rule identity, so it cannot be verified against the current rules; %s\", s.SessionID, resumeHint)\n\t}\n\tif m.Execution.RuleConfigSHA256 != id.RuleConfigSHA256 {\n\t\t// The digest is one aggregate, so it can only be attributed to a layer,\n\t\t// never to a specific rule or pattern.\n\t\treturn fmt.Errorf(\"resume rejected: review rule identity changed — either a rule text layer (custom, project, global or system) or the include/exclude file filter differs from session %q; %s\", s.SessionID, resumeHint)\n\t}\n\treturn nil\n}\n\n// explicitFlagHint renders the actionable half of a transition rejection. value\n// is empty whenever the endpoint has no provider name — one configured straight\n// from environment variables has none — and `pass --provider ` is not a command","sourceCodeStart":96,"sourceCodeEnd":132,"githubUrl":"https://github.com/alibaba/open-code-review/blob/5cf97d0d15cbd41b602513c4be3bfec3cee5bf7f/internal/session/resume_identity.go#L96-L132","documentation":"validateInputIdentity rejects resuming when the repository identity digest (Repository.IdentitySHA256) differs from the current repository's identity. A changed identity means the current repository is not the one the parent run reviewed — resume would compare results across unrelated repositories. An empty digest on both sides (no remote) counts as unchanged.","triggerScenarios":"ValidateResume where m.Repository.IdentitySHA256 != id.RepositorySHA256 — e.g. resuming in a different clone, after changing the git remote URL, or in a different fork.","commonSituations":"Cloning the repo to a new path/machine with a different or missing remote; switching between HTTPS and SSH remotes or between fork and upstream; CI checking out a different repository than the one that started the run.","solutions":["Resume from the same clone/remote used by the parent session","Restore the original remote URL (git remote set-url) so the repository identity matches","Start a new review in the current repository instead of resuming"],"exampleFix":"// before\ngit remote set-url origin https://github.com/me/fork.git  # identity changed\n// after\ngit remote set-url origin https://github.com/org/upstream.git  # restore original remote, then resume","handlingStrategy":"validation","validationCode":"// Confirm the repository identity matches before resuming\nif sess.Manifest != nil && sess.Manifest.Repository.IdentitySHA256 != currentRepoIdentitySHA256 {\n    return fmt.Errorf(\"different repository/remote; resume from the original clone\")\n}","typeGuard":null,"tryCatchPattern":"if err := ValidateResume(s, req); err != nil {\n    if strings.Contains(err.Error(), \"repository identity changed\") {\n        return startNewReview(req) // different repo — cannot reuse parent results\n    }\n    return err\n}","preventionTips":["Resume from the same clone with the same remote URL that started the run","Avoid switching remotes (fork vs upstream, HTTPS vs SSH) between run and resume","Ensure CI checks out the same repository as the parent run"],"tags":["session","resume","repository","git"],"backgroundTag":"resume-state-mismatch","analyzedSha":"5cf97d0d15cbd41b602513c4be3bfec3cee5bf7f","analyzedAt":"2026-09-02T02:08:09.116Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}