{"record":{"id":"d509d08abb673471","repo":"alibaba/open-code-review","slug":"resume-rejected-input-mode-changed-from-q-to-q","errorCode":null,"errorMessage":"resume rejected: input mode changed from %q to %q; %s","messagePattern":"resume rejected: input mode changed from %q to %q; (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/session/resume_identity.go","lineNumber":110,"sourceCode":"\t\t// looking for a crash that never happened. A session_end with no manifest\n\t\t// is a session older than run manifests, or a run that failed before\n\t\t// freezing one.\n\t\treturn fmt.Errorf(\"resume session %q closed without a run manifest, so its input identity cannot be verified — it either predates run manifests or failed before recording one; %s\", s.SessionID, resumeHint)\n\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}","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/alibaba/open-code-review/blob/5cf97d0d15cbd41b602513c4be3bfec3cee5bf7f/internal/session/resume_identity.go#L92-L128","documentation":"validateInputIdentity rejects resuming when the input mode recorded in the manifest differs from the current request's mode. Mode feeds item_id derivation, so parent and child items cannot even be aligned side by side — resuming across modes would corrupt reuse of prior results.","triggerScenarios":"ValidateResume where m.Input.Mode != id.Mode — e.g. the parent run used one review input mode (such as a diff/ref mode) and the resume request selected a different mode (file-set vs ref).","commonSituations":"User changes the review mode flag or config default between the original run and the resume; running resume from a different context (local vs CI) where a different mode is the default.","solutions":["Re-run resume with the same mode used by the parent session (check the session manifest/config)","Start a new review under the new mode instead of resuming","Update the config/flags so the mode matches the parent run"],"exampleFix":"// before\nocr review --resume abc123 --mode files   # parent used ref mode\n// after\nocr review --resume abc123 --mode ref     # match parent mode","handlingStrategy":"validation","validationCode":"// Match the parent session's input mode before resuming\nif sess.Manifest != nil && sess.Manifest.Input.Mode != currentRequestMode {\n    return fmt.Errorf(\"parent used mode %q; re-run with that mode or start fresh\",\n        sess.Manifest.Input.Mode)\n}","typeGuard":"func modeMatches(m *session.Manifest, want string) bool {\n    return m != nil && m.Input.Mode == want\n}","tryCatchPattern":"if err := ValidateResume(s, req); err != nil {\n    if strings.Contains(err.Error(), \"input mode changed\") {\n        return startNewReview(req) // mode changes require a fresh run\n    }\n    return err\n}","preventionTips":["Keep the review mode fixed in config across local and CI environments","Store the mode alongside the session ID in automation","Never flip --mode on a resume; treat a mode change as a new review"],"tags":["session","resume","mode","input"],"backgroundTag":"resume-state-mismatch","analyzedSha":"5cf97d0d15cbd41b602513c4be3bfec3cee5bf7f","analyzedAt":"2026-09-02T02:08:09.116Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}