{"record":{"id":"910b7cb1b0884ddc","repo":"alibaba/open-code-review","slug":"finalize-session-w-910b7c","errorCode":null,"errorMessage":"finalize session: %w","messagePattern":"finalize session: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/scan/agent.go","lineNumber":343,"sourceCode":"\ta.injectScanContentMap()\n\ta.args.Tools.Freeze()\n\n\ttotalDiscovered := len(a.items)\n\ta.items = a.filterScanItems(a.items)\n\ta.items = a.filterLargeScans(a.items)\n\n\treviewable := len(a.items)\n\tfmt.Fprintf(stdout.Writer(), \"[ocr] full-scan: %d file(s) discovered, reviewing %d in %s\\n\",\n\t\ttotalDiscovered, reviewable, a.args.RepoDir)\n\n\tif reviewable == 0 {\n\t\tfmt.Fprintln(stdout.Writer(), \"[ocr] No reviewable files. Skipping scan.\")\n\t\ttelemetry.Event(ctx, \"scan.no.files\")\n\t\t// A clean skip still has to reach disk: if session_end never persisted,\n\t\t// the skip cannot be claimed. Scan has no manifest builder, but the\n\t\t// session_end delivery contract still applies.\n\t\tif ferr := a.session.Finalize(); ferr != nil {\n\t\t\treturn []model.LlmComment{}, fmt.Errorf(\"finalize session: %w\", ferr)\n\t\t}\n\t\treturn []model.LlmComment{}, nil\n\t}\n\n\t// Pre-run cost projection so users aren't surprised by a large scan.\n\test := estimateCost(a.items, a.planEnabled(), a.dedupEnabled(), a.summaryEnabled())\n\tfmt.Fprintf(stdout.Writer(), \"[ocr] estimated cost: %s\\n\", est)\n\tif a.args.MaxTokensBudget > 0 {\n\t\tfmt.Fprintf(stdout.Writer(), \"[ocr] token budget: %s (dispatch stops once exceeded)\\n\", humanTokens(a.args.MaxTokensBudget))\n\t\tif est.TotalTokens > a.args.MaxTokensBudget {\n\t\t\tfmt.Fprintf(stdout.Writer(), \"[ocr] WARNING: estimate (%s) exceeds budget (%s); scan will stop partway\\n\",\n\t\t\t\thumanTokens(est.TotalTokens), humanTokens(a.args.MaxTokensBudget))\n\t\t}\n\t}\n\n\ta.currentDate = time.Now().Format(\"2006-01-02 15:04\")\n\ttelemetry.Event(ctx, \"scan.started\",\n\t\ttelemetry.AnyToAttr(\"file.count\", totalDiscovered),","sourceCodeStart":325,"sourceCodeEnd":361,"githubUrl":"https://github.com/alibaba/open-code-review/blob/5cf97d0d15cbd41b602513c4be3bfec3cee5bf7f/internal/scan/agent.go#L325-L361","documentation":"When the scan finds no reviewable files, Run still persists the session end (session_end must reach disk so the run can be 'claimed'). If session.Finalize() fails during that clean-skip path, the skip is abandoned and this 'finalize session: %w' error is returned, signaling the delivery contract was not satisfied.","triggerScenarios":"A scan where all files were filtered out (\"No reviewable files. Skipping scan.\") while a.session.Finalize() fails — typically a filesystem write failure to the session/state directory.","commonSituations":"Read-only filesystem or full disk where ocr persists session state; permissions problem on the state directory; state directory removed concurrently (e.g. another ocr process cleaned it).","solutions":["Check writability and free space of the directory where ocr persists session state (fix permissions or free disk space)","Re-run the scan after fixing storage; a persisted session_end is required for the run to be claimable","Investigate the wrapped ferr for the exact OS-level cause (path, errno)"],"exampleFix":"// before — state dir not writable\n$ ocr review  # finalize session: open .../session_end.json: permission denied\n// after\n$ chmod u+w ~/.ocr/state && ocr review","handlingStrategy":"try-catch","validationCode":"// ensure the state directory is writable before scanning\ndir := sessionStateDir()\nif err := os.MkdirAll(dir, 0o755); err != nil { return err }\nprobe := filepath.Join(dir, \".write_probe\")\nif err := os.WriteFile(probe, nil, 0o644); err != nil {\n    return fmt.Errorf(\"state dir %s not writable: %w\", dir, err)\n}\nos.Remove(probe)","typeGuard":null,"tryCatchPattern":"comments, err := agent.Run(ctx)\nif err != nil && strings.Contains(err.Error(), \"finalize session\") {\n    // session_end did not reach disk; fix storage/permissions and re-run\n    // so the run can be claimed\n}","preventionTips":["Keep the session state directory writable with sufficient free space","Avoid running concurrent ocr processes against the same state directory","Monitor disk usage on CI runners before large scans"],"tags":["persistence","filesystem","scan","session"],"backgroundTag":"state-persistence-failed","analyzedSha":"5cf97d0d15cbd41b602513c4be3bfec3cee5bf7f","analyzedAt":"2026-09-02T02:08:09.116Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}