{"record":{"id":"3758df93da12965d","repo":"siyuan-note/siyuan","slug":"encrypted-repository-data-is-missing-valid-noteboo","errorCode":null,"errorMessage":"encrypted repository data is missing valid notebook context","messagePattern":"encrypted repository data is missing valid notebook context","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/repository.go","lineNumber":399,"sourceCode":"\t\terr = errors.New(Conf.Language(26))\n\t\treturn\n\t}\n\n\tdata, file, err := readRepoFileWithAssets(fileID)\n\tif err != nil {\n\t\treturn\n\t}\n\n\tupdated = file.Updated\n\trepoPath := strings.TrimPrefix(file.Path, \"/\")\n\trepoPathParts := strings.SplitN(repoPath, \"/\", 2)\n\tpayloadBoxID := \"\"\n\tif len(repoPathParts) == 2 && ast.IsNodeIDPattern(repoPathParts[0]) {\n\t\tpayloadBoxID = repoPathParts[0]\n\t}\n\tif (util.IsCiphertext(data) || bytes.HasPrefix(data, encryptedAssetMagic)) &&\n\t\t(payloadBoxID == \"\" || !IsEncryptedBox(payloadBoxID)) {\n\t\terr = errors.New(\"encrypted repository data is missing valid notebook context\")\n\t\treturn\n\t}\n\n\tif strings.HasSuffix(file.Path, \".sy\") {\n\t\t// 加密笔记本的 .sy 在仓库里是密文，按路径提取 boxID 解密\n\t\tdata, err = decryptRepoDataIfNeeded(data, file.Path)\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\t\tluteEngine := NewLute()\n\t\tvar snapshotTree *parse.Tree\n\t\tdisplayInText, snapshotTree, err = parseTreeInSnapshot(data, luteEngine)\n\t\tif err != nil {\n\t\t\tlogging.LogErrorf(\"parse tree from snapshot file [%s] failed\", fileID)\n\t\t\treturn\n\t\t}\n\t\ttitle = snapshotTree.Root.IALAttr(\"title\")\n","sourceCodeStart":381,"sourceCodeEnd":417,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/model/repository.go#L381-L417","documentation":"OpenRepoSnapshotFile detected that the snapshot data is ciphertext (util.IsCiphertext or the encrypted-asset magic prefix) but the file path does not yield a valid encrypted-notebook boxID: the path lacks a node-ID-prefixed notebook segment, or that notebook is not registered as an encrypted box. Decryption cannot proceed without a trusted notebook context, so the read fails instead of guessing.","triggerScenarios":"Requesting a repo snapshot file whose payload is encrypted but whose path either has no notebook-ID prefix (repoPathParts[0] not a node-ID pattern), or references a notebook that IsEncryptedBox does not recognize (non-encrypted box, deleted/removed box, or plain notebook).","commonSituations":"Orphaned repo snapshot entries left after a notebook was deleted or converted from encrypted to plain; snapshots synced from an encrypted-notebook setup to a workspace lacking the box's encryption metadata; corrupted or hand-crafted repo paths passed to openRepoSnapshotFile.","solutions":["Verify the notebook referenced by the path still exists and is encrypted; restore/re-register it before reading its history","If the notebook was intentionally de-encrypted or deleted, treat these snapshot entries as unreachable and purge or ignore them","Sync the workspace fully so box encryption metadata (and the box itself) is present locally","Check that the file path passed to openRepoSnapshotFile is a raw repo path returned by repo APIs, not a rewritten/trimmed path"],"exampleFix":"// before: trimming the box prefix breaks context extraction\nconst relPath = repoPath.replace(/^\\/[0-9a-f-]{32}\\//, '/');\nawait fetchPost('/api/repo/openRepoSnapshotFile', { path: relPath });\n// after: pass the untouched repo path so the boxID prefix is preserved\nawait fetchPost('/api/repo/openRepoSnapshotFile', { path: repoPath });","handlingStrategy":"validation","validationCode":"const parts = repoPath.replace(/^\\//, '').split('/');\nconst isNodeID = /^[0-9]{14}-[0-9a-z]{7}$/.test(parts[0]);\nif (!isNodeID) throw new Error('Repo path missing notebook-ID prefix: ' + repoPath);","typeGuard":null,"tryCatchPattern":"try {\n  const res = await fetchPost('/api/repo/openRepoSnapshotFile', { id: fileID });\n} catch (e) {\n  if (String(e).includes('missing valid notebook context')) markSnapshotUnreadable(fileID);\n  else throw e;\n}","preventionTips":["Pass raw repo paths from repo APIs without rewriting them","Keep encrypted notebooks intact; convert/delete them only after purging their history entries","Ensure full sync so encrypted-box metadata is present before reading snapshots","Validate path shape (boxID prefix) in tooling before calling repo file APIs"],"tags":["repository","encryption","notebook","path"],"backgroundTag":"invalid-argument-value","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}