{"record":{"id":"1f0416f9b535279f","repo":"siyuan-note/siyuan","slug":"read-encrypted-index-setting-s-w","errorCode":null,"errorMessage":"read encrypted index setting %s: %w","messagePattern":"read encrypted index setting (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"kernel/util/encrypted_index.go","lineNumber":21,"sourceCode":"// SPDX-License-Identifier: AGPL-3.0-or-later\n\npackage util\n\nimport (\n\t\"database/sql\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n)\n\n// CheckEncryptedIndexCompatibility 将索引版本保存在受 SQLCipher 认证的表中，拒绝复用缺少版本或参数不匹配的旧索引。\n// schema 由各索引维护，修改表结构时递增；索引重建由已认证源文档的调用方负责。\nfunc CheckEncryptedIndexCompatibility(db *sql.DB, kind string, schema int) error {\n\tsettings := map[string]string{}\n\tfor _, name := range []string{\"cipher_version\", \"cipher_page_size\", \"kdf_iter\", \"cipher_hmac_algorithm\", \"cipher_kdf_algorithm\", \"cipher_use_hmac\"} {\n\t\tvar value string\n\t\tif err := db.QueryRow(\"PRAGMA \" + name).Scan(&value); err != nil {\n\t\t\treturn fmt.Errorf(\"read encrypted index setting %s: %w\", name, err)\n\t\t}\n\t\tif value == \"\" {\n\t\t\treturn fmt.Errorf(\"missing encrypted index setting %s\", name)\n\t\t}\n\t\tsettings[name] = value\n\t}\n\tencoded, err := json.Marshal(settings)\n\tif err != nil {\n\t\treturn err\n\t}\n\tvar metadataTables int\n\tif err = db.QueryRow(\"SELECT count(*) FROM sqlite_master WHERE type = 'table' AND name = 'encrypted_index_meta'\").Scan(&metadataTables); err != nil {\n\t\treturn err\n\t}\n\tif metadataTables == 0 {\n\t\tvar tables int\n\t\tif err = db.QueryRow(\"SELECT count(*) FROM sqlite_master WHERE type = 'table'\").Scan(&tables); err != nil {\n\t\t\treturn err","sourceCodeStart":3,"sourceCodeEnd":39,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/util/encrypted_index.go#L3-L39","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Check the wrapped cause (%w) to see whether it is 'file is not a database' (wrong format/key) vs. connection/corruption, then act accordingly.","If the index predates encrypted-index support, rebuild the index from the authenticated source documents rather than forcing the old db open.","Restore siyuan.db / blocktree.db from a backup or sync snapshot if the file is corrupted.","Verify the SQLCipher build/version matches the one that wrote the index (cipher_version mismatch) and keep the key-material configuration unchanged."],"exampleFix":"// before\ndb, _ := OpenEncryptedDB(path) // may fail: \"read encrypted index setting cipher_version: file is not a database\"\n// after\ndb, err := OpenEncryptedDB(path)\nif err != nil {\n    log.Warnf(\"encrypted index incompatible (%v); rebuilding from authenticated source\", err)\n    rebuildIndexFromDocuments(path) // caller-driven rebuild, never plaintext fallback\n}","handlingStrategy":"fallback","validationCode":"// before opening, confirm the file is a SQLCipher database with expected settings:\n// PRAGMA cipher_version;  -- must return a non-empty value\nrow := db.QueryRow(\"PRAGMA cipher_version\")\nvar v string\nif err := row.Scan(&v); err != nil || v == \"\" {\n    return errors.New(\"not a compatible encrypted index; rebuild required\")\n}","typeGuard":null,"tryCatchPattern":"if err := CheckEncryptedIndexCompatibility(db, kind, schema); err != nil {\n    log.Errorf(\"encrypted index incompatible: %v\", err)\n    // never fall back to plaintext; rebuild from authenticated source documents\n    return fmt.Errorf(\"encrypted index %s unusable, rebuild required: %w\", kind, err)\n}","preventionTips":["Never bypass authentication or fall back to plaintext when this error occurs — rebuild the index from authenticated sources instead.","Keep encrypted-index format versions and SQLCipher parameters (page size, KDF, HMAC) unchanged across upgrades.","Maintain recoverable backups/snapshots of siyuan.db and blocktree.db.","Test upgrades against fixtures from the previous encrypted format to catch compatibility breaks early."],"tags":["database","sqlite","sqlcipher","encryption","compatibility"],"backgroundTag":"database-query-failed","analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}