{"record":{"id":"36f8b2d0b4ef2af7","repo":"siyuan-note/siyuan","slug":"encrypted-document-history-is-missing-valid-notebo","errorCode":null,"errorMessage":"encrypted document history is missing valid notebook context","messagePattern":"encrypted document history is missing valid notebook context","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/history_diff.go","lineNumber":352,"sourceCode":"\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif !strings.HasSuffix(strings.ToLower(absPath), \".sy\") {\n\t\treturn nil, errors.New(\"history version is not a document\")\n\t}\n\trelPath, err := filepath.Rel(util.HistoryDir, absPath)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tparts := strings.SplitN(filepath.ToSlash(relPath), \"/\", 3)\n\tdata, err := filelock.ReadFile(absPath)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tciphertext := util.IsCiphertext(data)\n\tif ciphertext {\n\t\tif len(parts) < 3 || !ast.IsNodeIDPattern(parts[1]) || !IsEncryptedBox(parts[1]) {\n\t\t\treturn nil, errors.New(\"encrypted document history is missing valid notebook context\")\n\t\t}\n\t\tHoldBoxReadLock(parts[1])\n\t\tdefer ReleaseBoxReadLock(parts[1])\n\t\tdek, dekErr := GetDEKIfUnlocked(parts[1])\n\t\tif dekErr != nil {\n\t\t\treturn nil, errors.New(Conf.Language(314))\n\t\t}\n\t\tdata, err = DecryptFile(parts[1], parts[2], dek, data)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t} else if len(parts) >= 2 && IsEncryptedBox(parts[1]) {\n\t\treturn nil, fmt.Errorf(\"encrypted notebook document history is plaintext [%s]\", parts[1])\n\t}\n\n\trootID := strings.TrimSuffix(filepath.Base(absPath), filepath.Ext(absPath))\n\ttree, err := parseDocVersionTree(data, rootID)\n\thistoryRoot := filepath.Join(util.HistoryDir, parts[0])","sourceCodeStart":334,"sourceCodeEnd":370,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/model/history_diff.go#L334-L370","documentation":"When a history .sy file's bytes are detected as ciphertext, the path must contain a valid notebook (box) ID segment that identifies an encrypted notebook, so the file can be decrypted with that notebook's DEK. This error means the ciphertext history file cannot be associated with an encrypted notebook from its path (missing path segments, malformed notebook ID, or notebook not registered as encrypted).","triggerScenarios":"Loading a ciphertext history file whose path has fewer than 3 segments below HistoryDir, whose second segment is not a node-ID-pattern notebook ID, or whose notebook is not flagged as an encrypted box.","commonSituations":"Ciphertext history files copied/moved outside their notebook directory; a notebook removed from the encrypted-box list after history was written; manual reconstruction of history paths; restoring history data without its notebook context.","solutions":["Ensure the history path is under history/<timestamp>/<boxID>/<docID>.sy with a valid encrypted notebook ID","Confirm the notebook exists and is registered as an encrypted box (IsEncryptedBox)","Regenerate or re-import the history into the correct notebook directory"],"exampleFix":"// before\nloadDocVersion(\"history/20240101/orphan.sy\")\n// after\nloadDocVersion(\"history/20240101/20240101120000-boxid/doc.sy\")","handlingStrategy":"validation","validationCode":"const parts = relPath.split(\"/\"); if (parts.length < 3 || !isNodeID(parts[1]) || !isEncryptedBox(parts[1])) throw new Error(\"no valid encrypted notebook context\");","typeGuard":"const hasEncBoxContext = (parts: string[]) => parts.length >= 3 && /^[0-9]{14}-[0-9a-z]{7}$/.test(parts[1]);","tryCatchPattern":"try { await api.loadDocVersion(path); } catch (e) { if (String(e).includes(\"missing valid notebook context\")) { showToast(\"History entry cannot be tied to its encrypted notebook\"); } }","preventionTips":["Keep history files inside history/<timestamp>/<boxID>/ — never move them out","Do not unregister or delete an encrypted notebook before reviewing its history","Validate path structure before requesting encrypted history"],"tags":["history","encryption","path","notebook"],"backgroundTag":"invalid-argument-value","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"}