siyuan-note/siyuan · error

encrypted notebook asset history is plaintext [%s]

Error message

encrypted notebook asset history is plaintext [%s]

What it means

When rolling back an asset history that lives under an encrypted notebook's history directory, SiYuan requires the stored snapshot to actually be encrypted. The history file content was read and found to lack encryptedAssetMagic (i.e. plaintext) even though the path points into an encrypted notebook, so the rollback is rejected to avoid silently restoring unprotected data into an encrypted notebook.

Source

Thrown at kernel/model/history.go:567

	}

	from := historyPath
	// 从路径提取 boxID 判断是否加密笔记本的资源
	relPath := strings.TrimPrefix(filepath.ToSlash(historyPath), filepath.ToSlash(util.HistoryDir))
	relPath = strings.TrimPrefix(relPath, "/")
	pathParts := strings.SplitN(relPath, "/", 3)
	data, readErr := filelock.ReadFile(from)
	if readErr != nil {
		return readErr
	}
	encrypted := bytes.HasPrefix(data, encryptedAssetMagic)
	if encrypted && (len(pathParts) < 3 || !ast.IsNodeIDPattern(pathParts[1]) || !IsEncryptedBox(pathParts[1])) {
		return errors.New("encrypted asset history is missing valid notebook context")
	}
	to := filepath.Join(util.DataDir, "assets", filepath.Base(historyPath))
	if len(pathParts) >= 2 && IsEncryptedBox(pathParts[1]) {
		if !encrypted {
			return fmt.Errorf("encrypted notebook asset history is plaintext [%s]", pathParts[1])
		}
		// 加密笔记本的资源回滚到笔记本级 assets 目录
		to = filepath.Join(util.DataDir, pathParts[1], "assets", filepath.Base(historyPath))
		if err = os.MkdirAll(filepath.Dir(to), 0755); err != nil {
			return
		}
	}

	if err = filelock.CopyNewtimes(from, to); err != nil {
		logging.LogErrorf("copy file [%s] to [%s] failed: %s", from, to, err)
		return
	}
	IncSync()
	util.PushMsg(Conf.Language(102), 3000)
	return nil
}

// validateHistoryPath 校验历史路径是否位于工作区内且属于历史目录。

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Re-create the history snapshot so the asset is re-encrypted at write time, then roll back again
  2. Remove the stale plaintext history entry and re-generate history for that notebook
  3. Verify with the notebook encryption migration tooling that the notebook's history was re-encrypted after enabling encryption
  4. Do not hand-copy plaintext assets into data/history/ of encrypted notebooks

Example fix

// before: plaintext snapshot in encrypted notebook history
//   data/history/20240101120000-update/<encryptedBoxID>/assets/img.png
// after: re-generate the snapshot as ciphertext
//   data/history/20240101120000-update/<encryptedBoxID>/assets/img.png.enc
rollbackAssetsHistory("data/history/20240101120000-update/<encryptedBoxID>/assets/img.png.enc")
Defensive patterns

Strategy: validation

Validate before calling

// Pre-check snapshot content is ciphertext before rollback (read first bytes of the history file)
const head = await readHistoryFileHead(historyPath);
if (isEncryptedNotebook(boxID) && !hasEncryptedMagic(head)) {
  throw new Error("plaintext snapshot inside encrypted notebook history");
}

Type guard

null

Try / catch

try { await rollbackAssetsHistory(p); } catch (e) { if (String(e.msg).startsWith("encrypted notebook asset history is plaintext")) { await regenerateSnapshotEncrypted(p); await rollbackAssetsHistory(p); } else { throw e; } }

Prevention

When it happens

Trigger: Calling rollbackAssetsHistory with a historyPath under an encrypted notebook (IsEncryptedBox(pathParts[1]) is true) whose file on disk is plaintext — e.g. the snapshot was written before encryption or was tampered/decrypted externally.

Common situations: Restoring old history snapshots taken before the encrypted-notebook feature; a failed/interrupted encryption migration left plaintext snapshots; manual editing or copying of files inside data/history/; version downgrade/upgrade mixing encrypted and unencrypted history.

Understand the failure class

Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11). Data as JSON: /api/errors/2426131bd22943b7. Report an issue: GitHub.