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

  1. Verify the notebook referenced by the path still exists and is encrypted; restore/re-register it before reading its history
  2. If the notebook was intentionally de-encrypted or deleted, treat these snapshot entries as unreachable and purge or ignore them
  3. Sync the workspace fully so box encryption metadata (and the box itself) is present locally
  4. 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

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


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)