{"record":{"id":"58c6923f2bf7cb4d","repo":"siyuan-note/siyuan","slug":"encrypted-document-history-has-no-matching-noteboo","errorCode":null,"errorMessage":"encrypted document history has no matching notebook [%s]","messagePattern":"encrypted document history has no matching notebook \\[(.+?)\\]","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/history.go","lineNumber":188,"sourceCode":"\tdata, err := filelock.ReadFile(historyPath)\n\tif err != nil {\n\t\tlogging.LogErrorf(\"read file [%s] failed: %s\", historyPath, err)\n\t\treturn\n\t}\n\n\t// 加密笔记本的历史是密文，按路径里的 boxID 解密后解析\n\trelPath := strings.TrimPrefix(filepath.ToSlash(historyPath), filepath.ToSlash(util.HistoryDir))\n\trelPath = strings.TrimPrefix(relPath, \"/\")\n\tpathParts := strings.SplitN(relPath, \"/\", 3)\n\tciphertext := util.IsCiphertext(data)\n\tif ciphertext {\n\t\tif len(pathParts) < 3 || !ast.IsNodeIDPattern(pathParts[1]) {\n\t\t\terr = errors.New(\"encrypted document history is missing notebook context\")\n\t\t\treturn\n\t\t}\n\t\thistBoxID := pathParts[1]\n\t\tif !IsEncryptedBox(histBoxID) {\n\t\t\terr = fmt.Errorf(\"encrypted document history has no matching notebook [%s]\", histBoxID)\n\t\t\treturn\n\t\t}\n\t\tHoldBoxReadLock(histBoxID)\n\t\tdefer ReleaseBoxReadLock(histBoxID)\n\t\tdek, dekErr := GetDEKIfUnlocked(histBoxID)\n\t\tif dekErr != nil {\n\t\t\terr = errors.New(Conf.Language(314))\n\t\t\treturn\n\t\t}\n\t\tdata, err = DecryptFile(histBoxID, pathParts[2], dek, data)\n\t\tif err != nil {\n\t\t\tlogging.LogErrorf(\"decrypt history [%s] failed: %s\", historyPath, err)\n\t\t\treturn\n\t\t}\n\t} else if len(pathParts) >= 2 && IsEncryptedBox(pathParts[1]) {\n\t\terr = fmt.Errorf(\"encrypted notebook document history is plaintext [%s]\", pathParts[1])\n\t\treturn\n\t}","sourceCodeStart":170,"sourceCodeEnd":206,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/model/history.go#L170-L206","documentation":"For a ciphertext history file the kernel extracts histBoxID from the path and checks that a notebook with that ID actually exists (IsEncryptedBox). If no matching encrypted notebook exists, it errors 'encrypted document history has no matching notebook [%s]'. This prevents decrypting history without the owning notebook's context and keys.","triggerScenarios":"Viewing history of an encrypted notebook that has since been deleted, or whose ID changed (notebook recreated, restored from partial backup, sync conflict), so pathParts[1] names a nonexistent notebook.","commonSituations":"After deleting an encrypted notebook but browsing old history entries; restoring data/ from backup without the .si notebook folder; notebook ID mismatch after manual copying between workspaces.","solutions":["Recreate the encrypted notebook (or restore its .si folder) with the same notebook ID before opening the history entry","Copy the history entry back into a workspace where the matching notebook exists","If history is no longer needed, ignore the entry; it cannot be opened without the notebook's keys"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"// check notebook still exists before opening its history\nconst notebooks = (await fetchPost('/api/notebook/lsNotebooks', {})).notebooks;\nif (!notebooks.some(n => n.id === boxIDFromHistoryPath)) return null;","typeGuard":null,"tryCatchPattern":"try {\n  return await fetchPost('/api/history/getDocHistoryContent', {historyPath});\n} catch (e) {\n  if (String(e.msg).includes('no matching notebook')) {\n    return {content: null, reason: 'notebook deleted; history not openable'};\n  } else throw e;\n}","preventionTips":["When deleting an encrypted notebook, expect its history entries to become unreadable","Keep .si notebook folders intact when restoring backups","Filter history entries whose notebook no longer exists before rendering the history panel"],"tags":["history","encrypted-notebook","notebook-missing"],"backgroundTag":"entity-not-found","analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}