siyuan-note/siyuan · error
encrypted repository data is missing valid notebook context
Error message
encrypted repository data is missing valid notebook context
What it means
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.
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
Example fix
// before: trimming the box prefix breaks context extraction
const relPath = repoPath.replace(/^\/[0-9a-f-]{32}\//, '/');
await fetchPost('/api/repo/openRepoSnapshotFile', { path: relPath });
// after: pass the untouched repo path so the boxID prefix is preserved
await fetchPost('/api/repo/openRepoSnapshotFile', { path: repoPath }); Defensive patterns
Strategy: validation
Validate before calling
const parts = repoPath.replace(/^\//, '').split('/');
const isNodeID = /^[0-9]{14}-[0-9a-z]{7}$/.test(parts[0]);
if (!isNodeID) throw new Error('Repo path missing notebook-ID prefix: ' + repoPath); Try / catch
try {
const res = await fetchPost('/api/repo/openRepoSnapshotFile', { id: fileID });
} catch (e) {
if (String(e).includes('missing valid notebook context')) markSnapshotUnreadable(fileID);
else throw e;
} Prevention
- 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
When it happens
Trigger: 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).
Common situations: 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.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- encrypted repository data is missing notebook context
- encrypted repository data has no matching notebook
- cannot replay block swap across encrypted notebook…
- cannot swap blocks across encrypted notebook boundaries
- CLI does not support encrypted notebook
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/3758df93da12965d.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/model/repository.go:399
err = errors.New(Conf.Language(26))
return
}
data, file, err := readRepoFileWithAssets(fileID)
if err != nil {
return
}
updated = file.Updated
repoPath := strings.TrimPrefix(file.Path, "/")
repoPathParts := strings.SplitN(repoPath, "/", 2)
payloadBoxID := ""
if len(repoPathParts) == 2 && ast.IsNodeIDPattern(repoPathParts[0]) {
payloadBoxID = repoPathParts[0]
}
if (util.IsCiphertext(data) || bytes.HasPrefix(data, encryptedAssetMagic)) &&
(payloadBoxID == "" || !IsEncryptedBox(payloadBoxID)) {
err = errors.New("encrypted repository data is missing valid notebook context")
return
}
if strings.HasSuffix(file.Path, ".sy") {
// 加密笔记本的 .sy 在仓库里是密文,按路径提取 boxID 解密
data, err = decryptRepoDataIfNeeded(data, file.Path)
if err != nil {
return
}
luteEngine := NewLute()
var snapshotTree *parse.Tree
displayInText, snapshotTree, err = parseTreeInSnapshot(data, luteEngine)
if err != nil {
logging.LogErrorf("parse tree from snapshot file [%s] failed", fileID)
return
}
title = snapshotTree.Root.IALAttr("title")
View on GitHub (pinned to 9f775e8a12)