{"record":{"id":"2aa374f20bf3e494","repo":"siyuan-note/siyuan","slug":"encrypted-index-has-no-compatibility-metadata","errorCode":null,"errorMessage":"encrypted index has no compatibility metadata","messagePattern":"encrypted index has no compatibility metadata","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/util/encrypted_index.go","lineNumber":42,"sourceCode":"\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\")\n\t\t}\n\t\tif _, err = db.Exec(\"CREATE TABLE encrypted_index_meta (kind TEXT NOT NULL, schema_version INTEGER NOT NULL, cipher_settings TEXT NOT NULL)\"); err != nil {\n\t\t\treturn err\n\t\t}\n\t\t_, err = db.Exec(\"INSERT INTO encrypted_index_meta VALUES (?, ?, ?)\", kind, schema, string(encoded))\n\t\treturn err\n\t}\n\tvar storedKind, storedSettings string\n\tvar storedSchema, rows int\n\tif err = db.QueryRow(\"SELECT count(*) FROM encrypted_index_meta\").Scan(&rows); err != nil {\n\t\treturn err\n\t}\n\tif rows != 1 {\n\t\treturn errors.New(\"invalid encrypted index compatibility metadata\")\n\t}\n\tif err = db.QueryRow(\"SELECT kind, schema_version, cipher_settings FROM encrypted_index_meta\").Scan(&storedKind, &storedSchema, &storedSettings); err != nil {\n\t\treturn err\n\t}","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/util/encrypted_index.go#L24-L60","documentation":"After the cipher settings fingerprint is built, CheckEncryptedIndexCompatibility looks for the encrypted_index_meta table that stores kind, schema_version, and cipher_settings. If the table is absent but the database is NOT empty (tables > 0), the index was created by a build that predates compatibility metadata, and the library refuses to touch it rather than guess its format. If the database is empty, the metadata table is created and a row is inserted instead.","triggerScenarios":"Calling OpenEncryptedDB or OpenEncryptedBlockTreeDB on an existing encrypted index whose file contains other tables but no encrypted_index_meta table — i.e. an index created before the encrypted-notebook compatibility-metadata schema was introduced.","commonSituations":"Upgrading SiYuan from a pre-metadata encrypted-index build over an existing workspace; restoring an old history.db/blocktree.db backup; pointing a new kernel version at a workspace whose index files were generated by an older release.","solutions":["Delete the stale generated index (siyuan.db / blocktree.db) and let the kernel rebuild it from the .sy source documents — derived indexes are safe to rebuild","If rebuilding is not possible, open the index with the kernel version that created it, export data, then re-import into the new version","Check docs/ENCRYPTED-NOTEBOOK.md for the supported migration path for old encrypted indexes before deleting anything"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"var n int\n_ = db.QueryRow(\"SELECT count(*) FROM sqlite_master WHERE type='table' AND name='encrypted_index_meta'\").Scan(&n)\nlegacy := n == 0","typeGuard":null,"tryCatchPattern":"if err := CheckEncryptedIndexCompatibility(db, kind, schema); err != nil {\n    if strings.Contains(err.Error(), \"no compatibility metadata\") {\n        return rebuildDerivedIndex() // sources are untouched\n    }\n    return err\n}","preventionTips":["Run the version that created the index first if docs/ENCRYPTED-NOTEBOOK.md requires migration","Keep regular backups of data/ sources, not just index files, so index rebuilds are cheap","Never hand-copy old blocktree.db/history.db into a newer workspace"],"tags":["sqlite","encryption","schema","migration"],"backgroundTag":"schema-validation-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"}