siyuan-note/siyuan · error

encrypted repository data is missing notebook context

Error message

encrypted repository data is missing notebook context

What it means

decryptRepoDataIfNeeded: the data is ciphertext (IsCiphertext or encryptedAssetMagic) but the file path splits into fewer than 2 parts or its first segment is not a valid node ID (20-char boxID). With no valid boxID the code cannot route decryption, and fail-closed semantics forbid treating ciphertext as plaintext. Distinct from 862 (payload-context check in the caller) and 867 (boxID valid but not a registered encrypted box).

Source

Thrown at kernel/model/repository.go:741

		}

		title = tree.Root.IALAttr("title")
		rootID = tree.Root.ID
	}
	return
}

// decryptRepoDataIfNeeded 判断仓库数据是否属于加密笔记本,如果是则按路径类型分流解密。
// file.Path 格式:/<boxID>/...
// .sy → DecryptFile,assets/* → DecryptAsset,storage/av/*.json → av.DecryptAVData。
// 密文缺少有效路径上下文、笔记本未解锁或认证失败时返回错误,不允许调用方按明文继续处理。
func decryptRepoDataIfNeeded(data []byte, filePath string) ([]byte, error) {
	relPath := strings.TrimPrefix(filePath, "/")
	parts := strings.SplitN(relPath, "/", 2)
	encryptedPayload := util.IsCiphertext(data) || bytes.HasPrefix(data, encryptedAssetMagic)
	if len(parts) < 2 || !ast.IsNodeIDPattern(parts[0]) {
		if encryptedPayload {
			return nil, errors.New("encrypted repository data is missing notebook context")
		}
		return data, nil
	}
	boxID := parts[0]
	if !IsEncryptedBox(boxID) {
		if encryptedPayload {
			return nil, fmt.Errorf("encrypted repository data has no matching notebook [%s]", boxID)
		}
		return data, nil
	}
	// 持读锁,防止 LockBox 在解密期间清 DEK/缓存
	HoldBoxReadLock(boxID)
	defer ReleaseBoxReadLock(boxID)
	dek, err := GetDEKIfUnlocked(boxID)
	if err != nil {
		return nil, errors.New(Conf.Language(314))
	}
	boxRelPath := parts[1]

View on GitHub (pinned to 251596fc0d)

Solutions

  1. Check the logged filePath and confirm it starts with /<20-char-boxID>/.
  2. If the repo index is corrupt, reset the data repo and rebuild from a known-good snapshot set.
  3. Do not strip or rewrite path prefixes to bypass the check — it exists to prevent decrypting ciphertext without a key.
Defensive patterns

Strategy: validation

Validate before calling

// Reject ciphertext whose path cannot yield a valid boxID
rel := strings.TrimPrefix(filePath, "/")
parts := strings.SplitN(rel, "/", 2)
encrypted := util.IsCiphertext(data) || bytes.HasPrefix(data, encryptedAssetMagic)
if encrypted && (len(parts) < 2 || !ast.IsNodeIDPattern(parts[0])) {
    return errors.New("encrypted repository data is missing notebook context")
}

Prevention

When it happens

Trigger: A snapshot object whose path is malformed (no /<boxID>/ prefix, or boxID segment not matching ast.IsNodeIDPattern) while its stored bytes are ciphertext; reached during rollback/open/export of such a file.

Common situations: Corrupted repo index pointing at a misnamed object; manually relocated/renamed snapshot files; cross-version repo store with a path-format change.

Related errors


AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12). Data as JSON: /api/errors/137d2d4384429836. Report an issue: GitHub.