{"record":{"id":"3730f4a624990daf","repo":"siyuan-note/siyuan","slug":"encrypted-repository-data-has-no-matching-notebook","errorCode":null,"errorMessage":"encrypted repository data has no matching notebook [%s]","messagePattern":"encrypted repository data has no matching notebook \\[(.+?)\\]","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/repository.go","lineNumber":748,"sourceCode":"\n// decryptRepoDataIfNeeded 判断仓库数据是否属于加密笔记本，如果是则按路径类型分流解密。\n// file.Path 格式：/<boxID>/...\n// .sy → DecryptFile，assets/* → DecryptAsset，storage/av/*.json → av.DecryptAVData。\n// 密文缺少有效路径上下文、笔记本未解锁或认证失败时返回错误，不允许调用方按明文继续处理。\nfunc decryptRepoDataIfNeeded(data []byte, filePath string) ([]byte, error) {\n\trelPath := strings.TrimPrefix(filePath, \"/\")\n\tparts := strings.SplitN(relPath, \"/\", 2)\n\tencryptedPayload := util.IsCiphertext(data) || bytes.HasPrefix(data, encryptedAssetMagic)\n\tif len(parts) < 2 || !ast.IsNodeIDPattern(parts[0]) {\n\t\tif encryptedPayload {\n\t\t\treturn nil, errors.New(\"encrypted repository data is missing notebook context\")\n\t\t}\n\t\treturn data, nil\n\t}\n\tboxID := parts[0]\n\tif !IsEncryptedBox(boxID) {\n\t\tif encryptedPayload {\n\t\t\treturn nil, fmt.Errorf(\"encrypted repository data has no matching notebook [%s]\", boxID)\n\t\t}\n\t\treturn data, nil\n\t}\n\t// 持读锁，防止 LockBox 在解密期间清 DEK/缓存\n\tHoldBoxReadLock(boxID)\n\tdefer ReleaseBoxReadLock(boxID)\n\tdek, err := GetDEKIfUnlocked(boxID)\n\tif err != nil {\n\t\treturn nil, errors.New(Conf.Language(314))\n\t}\n\tboxRelPath := parts[1]\n\t// 按路径类型分流\n\tif strings.HasPrefix(boxRelPath, \"assets/\") {\n\t\tdiskName := filepath.Base(boxRelPath)\n\t\tplain, decErr := DecryptAsset(boxID, diskName, dek, data)\n\t\tif decErr != nil {\n\t\t\treturn nil, decErr\n\t\t}","sourceCodeStart":730,"sourceCodeEnd":766,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/model/repository.go#L730-L766","documentation":"decryptRepoDataIfNeeded: the path's boxID segment is a valid node ID, but IsEncryptedBox(boxID) is false AND the bytes are ciphertext. This means the notebook is not registered as encrypted, so there is no DEK to decrypt with — fail-closed. The boxID is included in the message. Contrast with 866 (invalid boxID format) and 868 (valid encrypted box but locked).","triggerScenarios":"A snapshot object carries ciphertext for a notebook whose conf.json no longer marks it Encrypted (e.g. it was downgraded/removed), or ciphertext leaked into a normal notebook's path during a botched copy/restore.","commonSituations":"Notebook un-encrypted or deleted but ciphertext objects remain in the repo store; restoring a backup of conf.json that lost the Encrypted flag; cross-workspace repo copy.","solutions":["Verify whether the named boxID should be encrypted; if so, restore its .siyuan/conf.json with Encrypted=true and the same key material.","If the notebook genuinely is not encrypted, the ciphertext object is orphaned/corrupt — remove it or rebuild the repo index.","Restore from a consistent snapshot set where path and encryption flag agree."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Reject ciphertext whose boxID is not a registered encrypted notebook\nrel := strings.TrimPrefix(filePath, \"/\")\nparts := strings.SplitN(rel, \"/\", 2)\nif len(parts) == 2 && ast.IsNodeIDPattern(parts[0]) && !model.IsEncryptedBox(parts[0]) {\n    if util.IsCiphertext(data) || bytes.HasPrefix(data, encryptedAssetMagic) {\n        return fmt.Errorf(\"encrypted repository data has no matching notebook [%s]\", parts[0])\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep the Encrypted flag in each notebook's conf.json consistent with its stored objects.","When deleting/un-encrypting a notebook, clean up its ciphertext repo objects too.","Investigate any boxID reported in this message — it signals store/notebook mismatch."],"tags":["repo","encryption","data-integrity","fail-closed"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}