{"record":{"id":"eaf439255d3ac285","repo":"siyuan-note/siyuan","slug":"missing-encrypted-index-setting-s","errorCode":null,"errorMessage":"missing encrypted index setting %s","messagePattern":"missing encrypted index setting (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/util/encrypted_index.go","lineNumber":24,"sourceCode":"\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\n\t\t}\n\t\tif tables != 0 {\n\t\t\treturn errors.New(\"encrypted index has no compatibility metadata\")","sourceCodeStart":6,"sourceCodeEnd":42,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/util/encrypted_index.go#L6-L42","documentation":"OpenEncryptedDB/OpenEncryptedBlockTreeDB run this check after opening a SQLCipher-encrypted SQLite index. It reads SQLCipher PRAGMAs (cipher_version, cipher_page_size, kdf_iter, cipher_hmac_algorithm, cipher_kdf_algorithm, cipher_use_hmac) and requires each to return a non-empty value so the settings can be fingerprinted into compatibility metadata. An empty value means the database was not opened with SQLCipher (plain SQLite) or the SQLCipher build reports no setting, so the compatibility fingerprint cannot be recorded.","triggerScenarios":"CheckEncryptedIndexCompatibility is called on an *sql.DB whose underlying driver is plain SQLite instead of SQLCipher, so every 'PRAGMA cipher_*' query returns an empty string. Also triggered by a SQLCipher version that does not expose one of the six pragmas queried.","commonSituations":"Linking kernel against a stock mattn/go-sqlite3 build without the cipher tags; a dependency replace silently swapping the SQLCipher fork for vanilla SQLite; running on a platform where the cipher extension failed to compile in; opening a pre-encryption (legacy plaintext) siyuan.db through the encrypted-open path.","solutions":["Ensure the SQLite driver is the SQLCipher build (maintainer's fork with cipher support via kernel/go.mod replace) and rebuild the kernel binary","Verify with the same connection that PRAGMA cipher_version returns non-empty; if empty the binary was linked against plain SQLite","If the database is genuinely a legacy plaintext index, open it through the plain open path or migrate it to the encrypted format before calling OpenEncryptedDB","Check go.mod for accidental replaces of go-sqlite3 with an upstream non-cipher version and remove them"],"exampleFix":"// before: driver compiled without SQLCipher, PRAGMA cipher_version = \"\"\n// after: use the cipher-enabled fork and build tags in kernel/go.mod\nrequire github.com/siyuan-note/go-sqlite3 ...\n// keep the permanent replace pointing at the cipher-enabled fork","handlingStrategy":"validation","validationCode":"var v string\nif err := db.QueryRow(\"PRAGMA cipher_version\").Scan(&v); err != nil || v == \"\" {\n    return fmt.Errorf(\"driver is not SQLCipher-enabled\")\n}","typeGuard":null,"tryCatchPattern":"if err := CheckEncryptedIndexCompatibility(db, kind, schema); err != nil {\n    log.Printf(\"encrypted index unusable, rebuilding: %v\", err)\n    return rebuildIndexFromSources()\n}","preventionTips":["Always build the kernel with the cipher-enabled SQLite fork from kernel/go.mod","Smoke-test PRAGMA cipher_version at startup before opening encrypted indexes","Never add temporary replaces of go-sqlite3 that drop cipher support"],"tags":["sqlite","sqlcipher","encryption","database"],"backgroundTag":"missing-config-value","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"}