{"record":{"id":"97f9b54598edafa8","repo":"siyuan-note/siyuan","slug":"encrypted-snapshot-document-is-missing-valid-noteb","errorCode":null,"errorMessage":"encrypted snapshot document is missing valid notebook context","messagePattern":"encrypted snapshot document is missing valid notebook context","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/history_diff.go","lineNumber":424,"sourceCode":"\t\treturn nil, err\n\t}\n\tfile, err := repo.GetFile(fileID)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif !strings.HasSuffix(strings.ToLower(file.Path), \".sy\") {\n\t\treturn nil, errors.New(\"snapshot version is not a document\")\n\t}\n\trepoPath := strings.TrimPrefix(file.Path, \"/\")\n\tpathParts := strings.SplitN(repoPath, \"/\", 2)\n\tdata, err := repo.OpenFile(file)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tciphertext := util.IsCiphertext(data)\n\tif ciphertext {\n\t\tif len(pathParts) < 2 || !ast.IsNodeIDPattern(pathParts[0]) || !IsEncryptedBox(pathParts[0]) {\n\t\t\treturn nil, errors.New(\"encrypted snapshot document is missing valid notebook context\")\n\t\t}\n\t\tHoldBoxReadLock(pathParts[0])\n\t\tdefer ReleaseBoxReadLock(pathParts[0])\n\t\tdek, unlockErr := GetDEKIfUnlocked(pathParts[0])\n\t\tif unlockErr != nil {\n\t\t\treturn nil, errors.New(Conf.Language(314))\n\t\t}\n\t\tdata, err = DecryptFile(pathParts[0], pathParts[1], dek, data)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t} else if len(pathParts) > 0 && IsEncryptedBox(pathParts[0]) {\n\t\treturn nil, fmt.Errorf(\"encrypted notebook snapshot document is plaintext [%s]\", pathParts[0])\n\t}\n\trootID := strings.TrimSuffix(filepath.Base(file.Path), filepath.Ext(file.Path))\n\ttree, err := parseDocVersionTree(data, rootID)\n\tboxID := \"\"\n\tif 0 < len(pathParts) && ast.IsNodeIDPattern(pathParts[0]) {","sourceCodeStart":406,"sourceCodeEnd":442,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/model/history_diff.go#L406-L442","documentation":"A ciphertext snapshot document must map to a valid encrypted notebook via its repo path (first path segment being a node-ID-pattern box ID of an encrypted notebook) so the right DEK can be used. This error means the ciphertext file's path lacks a usable notebook context — wrong number of segments, malformed box ID, or box not registered as encrypted.","triggerScenarios":"Opening a ciphertext snapshot whose repo path has fewer than 2 segments, whose first segment is not a valid node-ID notebook ID, or whose box is not an encrypted notebook.","commonSituations":"Snapshot files relocated outside the expected /<boxID>/<docPath> layout; notebook deleted or converted to non-encrypted after the snapshot was taken; manually crafted repo file paths.","solutions":["Ensure the snapshot path is /<boxID>/<docPath>.sy with a valid encrypted notebook ID","Confirm the notebook still exists and is registered encrypted (IsEncryptedBox)","Re-snapshot or re-import the document into a valid encrypted notebook"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const segs = filePath.replace(/^\\//, \"\").split(\"/\"); if (segs.length < 2 || !isNodeID(segs[0]) || !isEncryptedBox(segs[0])) throw new Error(\"no valid encrypted notebook context\");","typeGuard":"const hasEncBoxCtx = (path: string) => { const s = path.replace(/^\\//, \"\").split(\"/\"); return s.length >= 2 && /^[0-9]{14}-[0-9a-z]{7}$/.test(s[0]); };","tryCatchPattern":"try { await api.loadDocVersion(fileID); } catch (e) { if (String(e).includes(\"missing valid notebook context\")) { showToast(\"Snapshot path has no encrypted notebook context\"); } }","preventionTips":["Never rewrite or flatten repo paths for snapshot files","Keep encrypted notebooks alive while their snapshots are still browsable","Validate the /<boxID>/<docPath> shape before snapshot version calls"],"tags":["snapshot","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-14T00:17:10.932Z"}