{"record":{"id":"bf9d63b495f45126","repo":"siyuan-note/siyuan","slug":"encrypted-notebook-snapshot-document-is-plaintext","errorCode":null,"errorMessage":"encrypted notebook snapshot document is plaintext [%s]","messagePattern":"encrypted notebook snapshot document is plaintext \\[(.+?)\\]","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/history_diff.go","lineNumber":437,"sourceCode":"\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]) {\n\t\tboxID = pathParts[0]\n\t}\n\tif err != nil {\n\t\treturn &loadedDocVersion{\n\t\t\ttitle:    rootID,\n\t\t\trootID:   rootID,\n\t\t\traw:      data,\n\t\t\tparseErr: err,\n\t\t\tlarge:    1024*1024 <= len(data),\n\t\t\tboxID:    boxID,\n\t\t}, nil\n\t}\n\treturn &loadedDocVersion{","sourceCodeStart":419,"sourceCodeEnd":455,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/model/history_diff.go#L419-L455","documentation":"The snapshot document belongs to an encrypted notebook (IsEncryptedBox) but its stored bytes are plaintext. The kernel refuses to read unencrypted content from an encrypted notebook's snapshot store, preserving the guarantee that encrypted notebooks never expose plaintext data at rest.","triggerScenarios":"Opening a snapshot for an encrypted notebook where the repo-stored .sy content is unencrypted — written by a non-encrypting path or manually uploaded from a plain notebook.","commonSituations":"Migrating a plain notebook into encrypted storage without re-encrypting snapshots; a bug in snapshot write paths; manually injecting plaintext files into the repo store.","solutions":["Re-snapshot the document so it is encrypted under the notebook's DEK","Remove the plaintext snapshot and rebuild the snapshot index","Verify the notebook's encrypted status matches how its data is actually stored"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"if (isEncryptedBox(boxID) && !util.isCiphertext(data)) throw new Error(\"snapshot must be ciphertext\");","typeGuard":null,"tryCatchPattern":"try { await api.loadDocVersion(fileID); } catch (e) { if (String(e).includes(\"is plaintext\")) { showToast(\"Snapshot is corrupt; rebuild snapshots for this notebook\"); } }","preventionTips":["Re-snapshot documents after converting a notebook to encrypted","Never manually place plaintext files into an encrypted notebook's repo store","Use only kernel write paths for snapshot data"],"tags":["snapshot","encryption","plaintext","notebook"],"backgroundTag":"incompatible-source-type","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"}