siyuan-note/siyuan · error
encrypted notebook document history is plaintext [%s]
Error message
encrypted notebook document history is plaintext [%s]
What it means
The history file belongs to an encrypted notebook (IsEncryptedBox) but its bytes are plaintext, not ciphertext. The kernel requires document history in encrypted notebooks to be stored encrypted; plaintext content there violates the format invariant, so it is rejected instead of silently reading unencrypted data.
Source
Thrown at kernel/model/history_diff.go:365
return nil, err
}
ciphertext := util.IsCiphertext(data)
if ciphertext {
if len(parts) < 3 || !ast.IsNodeIDPattern(parts[1]) || !IsEncryptedBox(parts[1]) {
return nil, errors.New("encrypted document history is missing valid notebook context")
}
HoldBoxReadLock(parts[1])
defer ReleaseBoxReadLock(parts[1])
dek, dekErr := GetDEKIfUnlocked(parts[1])
if dekErr != nil {
return nil, errors.New(Conf.Language(314))
}
data, err = DecryptFile(parts[1], parts[2], dek, data)
if err != nil {
return nil, err
}
} else if len(parts) >= 2 && IsEncryptedBox(parts[1]) {
return nil, fmt.Errorf("encrypted notebook document history is plaintext [%s]", parts[1])
}
rootID := strings.TrimSuffix(filepath.Base(absPath), filepath.Ext(absPath))
tree, err := parseDocVersionTree(data, rootID)
historyRoot := filepath.Join(util.HistoryDir, parts[0])
boxID := ""
if len(parts) >= 2 && ast.IsNodeIDPattern(parts[1]) {
boxID = parts[1]
}
if err != nil {
return &loadedDocVersion{
title: rootID,
rootID: rootID,
raw: data,
parseErr: err,
large: 1024*1024 <= len(data),
boxID: boxID,
history: historyRoot,View on GitHub (pinned to 8641553a1f)
Solutions
- Re-generate the history entry so the document is stored encrypted for that notebook
- Move the history to a non-encrypted notebook if plaintext storage was intended
- Remove the stale plaintext history entry and re-snapshot the document
Defensive patterns
Strategy: validation
Validate before calling
if (isEncryptedBox(boxID) && !util.isCiphertext(data)) throw new Error("expected ciphertext for encrypted notebook"); Try / catch
try { await api.loadDocVersion(path); } catch (e) { if (String(e).includes("is plaintext")) { showToast("History entry is corrupt; re-snapshot the document"); } } Prevention
- Never copy plaintext .sy files into an encrypted notebook's history directory
- Only use kernel APIs to write history for encrypted notebooks
- Audit history directories after toggling a notebook between plain and encrypted
When it happens
Trigger: Loading history for an encrypted notebook where the .sy file under history/ is stored unencrypted — e.g. the file was written by a non-encrypting code path or manually copied from a normal notebook.
Common situations: Copying a plain notebook's history into an encrypted notebook's directory; a history-writing bug storing unencrypted data; toggling a notebook to encrypted after history existed in plaintext.
Understand the failure class
Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.
Related errors
- encrypted notebook attribute view history is plaintext [%s]
- encrypted document history is missing valid notebook context
- encrypted notebook snapshot document is plaintext [%s]
- Related operations are being processed, please try again lat
- Encrypted notebooks do not support this operation
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/137463c728e3ae65.
Report an issue: GitHub.