{"record":{"id":"18b4312e14f779fb","repo":"alibaba/open-code-review","slug":"resume-session-q-selected-no-input-so-it-has-not","errorCode":null,"errorMessage":"resume session %q selected no input, so it has nothing to resume; %s","messagePattern":"resume session %q selected no input, so it has nothing to resume; (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/session/resume_identity.go","lineNumber":104,"sourceCode":"\tcase m == nil && !s.Closed:\n\t\t// Distinguishing all of these from \"manifest present, zero completed\n\t\t// items\" is the whole point: that one is resumable, none of these are.\n\t\treturn fmt.Errorf(\"resume session %q was interrupted before it closed, so it never recorded a run manifest and its input identity cannot be verified; %s\", s.SessionID, resumeHint)\n\tcase m == nil:\n\t\t// It closed cleanly, so blaming an interruption would send the user\n\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 {","sourceCodeStart":86,"sourceCodeEnd":122,"githubUrl":"https://github.com/alibaba/open-code-review/blob/5cf97d0d15cbd41b602513c4be3bfec3cee5bf7f/internal/session/resume_identity.go#L86-L122","documentation":"validateInputIdentity rejects resuming a session whose manifest selected no input (empty Coverage.Selected). Without selected input, parent and child would hash to the same canonical empty digest, pass every comparison, and produce a resumed run that reuses nothing and dispatches nothing — so it is rejected as meaningless.","triggerScenarios":"ValidateResume where len(m.Coverage.Selected) == 0 — the parent review ran against an empty change set / empty file selection and recorded nothing to resume from.","commonSituations":"Resuming a review of a PR or diff that had no changed files; a run where the mode/ref resolved to zero files; resuming the wrong (empty) session.","solutions":["Start a new review with actual input instead of resuming an empty run","Check that the target branch/PR/refs actually contain changes and re-run the review","Verify you are resuming the intended (non-empty) session ID"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Skip resume for sessions that selected no input\nif sess.Manifest != nil && len(sess.Manifest.Coverage.Selected) == 0 {\n    return fmt.Errorf(\"session %s selected no input; start a new review\", sess.SessionID)\n}","typeGuard":"func hasSelectableInput(m *session.Manifest) bool {\n    return m != nil && len(m.Coverage.Selected) > 0\n}","tryCatchPattern":"if err := ValidateResume(s, req); err != nil {\n    if strings.Contains(err.Error(), \"selected no input\") {\n        return startNewReview(req)\n    }\n    return err\n}","preventionTips":["Verify the diff/PR actually has changes before starting a review","Check the mode/ref resolves to a non-empty file set before resuming","Empty reviews are dead ends — treat them as fresh-run candidates only"],"tags":["session","resume","empty-input","coverage"],"backgroundTag":"resume-unverifiable-session","analyzedSha":"5cf97d0d15cbd41b602513c4be3bfec3cee5bf7f","analyzedAt":"2026-09-02T02:08:09.116Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}