{"record":{"id":"99de803579149303","repo":"siyuan-note/siyuan","slug":"conf-language-371","errorCode":null,"errorMessage":"Conf.Language(371)","messagePattern":"Conf\\.Language\\(371\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/history.go","lineNumber":644,"sourceCode":"\nfunc RollbackNotebookHistory(historyPath string) (err error) {\n\thistoryPath, err = validateHistoryPath(historyPath)\n\tif err != nil {\n\t\treturn\n\t}\n\tboxID, err := validateNotebookHistoryPath(historyPath)\n\tif err != nil {\n\t\treturn\n\t}\n\tif _, loaded := boxLock.LoadOrStore(boxID, true); loaded {\n\t\treturn errors.New(Conf.Language(239))\n\t}\n\tdefer boxLock.Delete(boxID)\n\n\tfrom := historyPath\n\tto := filepath.Join(util.DataDir, boxID)\n\tif filelock.IsExist(to) {\n\t\treturn errors.New(Conf.Language(371))\n\t}\n\n\tif err = filelock.CopyNewtimes(from, to); err != nil {\n\t\tlogging.LogErrorf(\"copy file [%s] to [%s] failed: %s\", from, to, err)\n\t\treturn\n\t}\n\n\tIncSync()\n\tReloadFiletree()\n\tutil.PushMsg(Conf.Language(372), 3000)\n\treturn nil\n}\n\nfunc validateNotebookHistoryPath(historyPath string) (boxID string, err error) {\n\trel, err := filepath.Rel(util.HistoryDir, historyPath)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"invalid notebook history path [%s]\", historyPath)\n\t}","sourceCodeStart":626,"sourceCodeEnd":662,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/model/history.go#L626-L662","documentation":"RollbackNotebookHistory restores a deleted notebook from history to data/<boxID>. Before copying, it checks whether the target directory already exists (filelock.IsExist) and aborts with the localized message Conf.Language(371) to avoid overwriting or merging with a live notebook that now occupies the same ID.","triggerScenarios":"Calling rollbackNotebookHistory for a notebook whose ID directory already exists in the workspace — e.g. the notebook was recreated after deletion (new data under the same ID), the deletion history is old, or a sync brought the notebook back before the rollback ran.","commonSituations":"User deleted a notebook, then re-imported/re-created it, then tried to restore the old snapshot; duplicate ID collisions after copying notebooks between workspaces; sync resolving a deletion independently on another device; stale history panel entry for an already-restored notebook.","solutions":["Open the existing notebook to confirm whether the restore is still needed; if it is already restored, skip the rollback","Move/rename the existing data/<boxID> directory out of the workspace if you intentionally want to replace it with the historical version, then roll back","Roll back to a different notebook by first clearing the conflicting data — do not attempt to merge","Refresh the history list; the deletion entry is likely stale"],"exampleFix":"// before: blind retry keeps failing\nrollbackNotebookHistory(historyPath);\n// after: check target first and clear intentionally\nif (exists(workspaceDir + \"/data/<boxID>\")) {\n  rename(workspaceDir + \"/data/<boxID>\", backupDir + \"/<boxID>.bak\");\n}\nrollbackNotebookHistory(historyPath);","handlingStrategy":"validation","validationCode":"async function notebookAlreadyExists(boxID) {\n  const r = await fetchPost(\"/api/filetree/checkFileExist\", {path: \"/data/\" + boxID});\n  return r.code === 0 && r.data.isExist === true;\n}","typeGuard":"null","tryCatchPattern":"try { await rollbackNotebookHistory(p); } catch (e) { if (isNotebookExistsMessage(e)) { /* prompt user: notebook already exists, skip or replace manually */ } else { throw e; } }","preventionTips":["Check whether the notebook was re-created before attempting rollback","Do not reuse notebook IDs when re-importing deleted notebooks","Refresh the history list so stale delete entries are not re-rolled"],"tags":["history","rollback","conflict","notebook"],"backgroundTag":"file-already-exists","analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}