siyuan-note/siyuan · critical

read encrypted index setting %s: %w

Error message

read encrypted index setting %s: %w

What it means

CheckEncryptedIndexCompatibility reads six SQLCipher PRAGMA settings (cipher_version, cipher_page_size, kdf_iter, cipher_hmac_algorithm, cipher_kdf_algorithm, cipher_use_hmac) from an encrypted index database to verify schema/key compatibility. This error wraps a failure of the PRAGMA query itself (db.QueryRow(...).Scan), e.g. the database is not a SQLCipher database, is corrupted, or the connection is unusable.

Source

Thrown at kernel/util/encrypted_index.go:21

// SPDX-License-Identifier: AGPL-3.0-or-later

package util

import (
	"database/sql"
	"encoding/json"
	"errors"
	"fmt"
)

// CheckEncryptedIndexCompatibility 将索引版本保存在受 SQLCipher 认证的表中,拒绝复用缺少版本或参数不匹配的旧索引。
// schema 由各索引维护,修改表结构时递增;索引重建由已认证源文档的调用方负责。
func CheckEncryptedIndexCompatibility(db *sql.DB, kind string, schema int) error {
	settings := map[string]string{}
	for _, name := range []string{"cipher_version", "cipher_page_size", "kdf_iter", "cipher_hmac_algorithm", "cipher_kdf_algorithm", "cipher_use_hmac"} {
		var value string
		if err := db.QueryRow("PRAGMA " + name).Scan(&value); err != nil {
			return fmt.Errorf("read encrypted index setting %s: %w", name, err)
		}
		if value == "" {
			return fmt.Errorf("missing encrypted index setting %s", name)
		}
		settings[name] = value
	}
	encoded, err := json.Marshal(settings)
	if err != nil {
		return err
	}
	var metadataTables int
	if err = db.QueryRow("SELECT count(*) FROM sqlite_master WHERE type = 'table' AND name = 'encrypted_index_meta'").Scan(&metadataTables); err != nil {
		return err
	}
	if metadataTables == 0 {
		var tables int
		if err = db.QueryRow("SELECT count(*) FROM sqlite_master WHERE type = 'table'").Scan(&tables); err != nil {
			return err

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Check the wrapped cause (%w) to see whether it is 'file is not a database' (wrong format/key) vs. connection/corruption, then act accordingly.
  2. If the index predates encrypted-index support, rebuild the index from the authenticated source documents rather than forcing the old db open.
  3. Restore siyuan.db / blocktree.db from a backup or sync snapshot if the file is corrupted.
  4. Verify the SQLCipher build/version matches the one that wrote the index (cipher_version mismatch) and keep the key-material configuration unchanged.

Example fix

// before
db, _ := OpenEncryptedDB(path) // may fail: "read encrypted index setting cipher_version: file is not a database"
// after
db, err := OpenEncryptedDB(path)
if err != nil {
    log.Warnf("encrypted index incompatible (%v); rebuilding from authenticated source", err)
    rebuildIndexFromDocuments(path) // caller-driven rebuild, never plaintext fallback
}
Defensive patterns

Strategy: fallback

Validate before calling

// before opening, confirm the file is a SQLCipher database with expected settings:
// PRAGMA cipher_version;  -- must return a non-empty value
row := db.QueryRow("PRAGMA cipher_version")
var v string
if err := row.Scan(&v); err != nil || v == "" {
    return errors.New("not a compatible encrypted index; rebuild required")
}

Try / catch

if err := CheckEncryptedIndexCompatibility(db, kind, schema); err != nil {
    log.Errorf("encrypted index incompatible: %v", err)
    // never fall back to plaintext; rebuild from authenticated source documents
    return fmt.Errorf("encrypted index %s unusable, rebuild required: %w", kind, err)
}

Prevention

When it happens

Trigger: Calling CheckEncryptedIndexCompatibility (directly or via OpenEncryptedDB / OpenEncryptedBlockTreeDB) on a database where `PRAGMA cipher_version` (or a sibling PRAGMA) cannot be scanned — non-SQLCipher/plain-SQLite file, wrong key already applied, corrupted db header, or a closed/pool-broken connection.

Common situations: Pointing the kernel at an old unencrypted index (pre-encrypted-notebook format); a workspace db corrupted or truncated; SQLCipher build mismatch so PRAGMA functions are unavailable; opening the db after a failed key derivation leaves the connection broken.

Understand the failure class

Background: Database query failed: Internal Server Error 500s wrapping SQL, Prisma, and connection failures — what to check first — this error's family across 16 libraries.

Related errors


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