{"record":{"id":"fb48dc705a1ab597","repo":"siyuan-note/siyuan","slug":"block-tree-database-is-unavailable","errorCode":null,"errorMessage":"block tree database is unavailable","messagePattern":"block tree database is unavailable","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"kernel/treenode/blocktree.go","lineNumber":52,"sourceCode":"\t\"github.com/88250/lute/parse\"\n\t\"github.com/siyuan-note/logging\"\n\t\"github.com/siyuan-note/siyuan/kernel/util\"\n)\n\ntype BlockTree struct {\n\tID       string // 块 ID\n\tRootID   string // 根 ID\n\tParentID string // 父 ID\n\tBoxID    string // 笔记本 ID\n\tPath     string // 文档数据路径\n\tHPath    string // 文档可读路径\n\tUpdated  string // 更新时间\n\tType     string // 类型\n}\n\nvar (\n\tdb                        *sql.DB\n\terrBlockTreeDBUnavailable = errors.New(\"block tree database is unavailable\")\n\n\tinitDatabaseLock = sync.RWMutex{}\n)\n\nfunc initDatabase(forceRebuild bool) {\n\tinitDatabaseLock.Lock()\n\tdefer initDatabaseLock.Unlock()\n\n\tinitDBConnection()\n\n\tif !forceRebuild {\n\t\tif !gulu.File.IsExist(util.BlockTreeDBPath) {\n\t\t\tforceRebuild = true\n\t\t}\n\t}\n\tif !forceRebuild {\n\t\t// 校验块树表是否可用，避免因上次重建被中断导致数据库文件存在但表缺失\n\t\tvar table string","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/treenode/blocktree.go#L34-L70","documentation":"errBlockTreeDBUnavailable, declared in kernel/treenode/blocktree.go. It is returned by scanQueryRow when the *sql.Row it received is nil, which happens when the package-level `db` handle is nil — i.e. initDatabase / initDBConnection has not run (or the kernel is shutting down). Callers like GetBlockTreeInExactBox treat it silently (not logged) because it is an init-order condition, not data corruption.","triggerScenarios":"Any blocktree read that goes through scanQueryRow (e.g. GetBlockTree, GetBlockTreeInExactBox) before initDatabase has established the global `db` handle, or after it has been torn down. The kernel's Boot sequence must call the treenode init before serving requests.","commonSituations":"Calling blocktree lookups during very early startup before the blocktree DB is opened; invoking operations after a fatal DB init failure (LogFatalf with ExitCodeUnavailableDatabase); races during shutdown.","solutions":["Ensure the kernel boot sequence has completed treenode.InitBlockTree / initDatabase before issuing block queries.","If init failed, inspect the kernel log for the preceding LogFatalf/LogErrorf about blocktree DB creation — the DB file may be locked, on a read-only volume, or corrupt.","Treat errBlockTreeDBUnavailable as a fatal init-order signal: surface it to the user rather than retrying blindly."],"exampleFix":"// before: blocktree read issued before boot finished\nbt := treenode.GetBlockTree(id) // returns nil, scan logs nothing\n\n// after: wait for init, then query\nif err := treenode.InitBlockTree(false); err != nil {\n    return fmt.Errorf(\"blocktree init failed: %w\", err)\n}\nbt := treenode.GetBlockTree(id)","handlingStrategy":"validation","validationCode":"// Confirm the blocktree db handle is live before querying.\nfunc ensureBlockTreeReady() error {\n    // Re-initialise if missing; initDatabase is idempotent under initDatabaseLock.\n    treenode.InitBlockTree(false) // or whatever the boot entry exposes\n    return nil\n}\n\nif err := ensureBlockTreeReady(); err != nil { return err }\nbt := treenode.GetBlockTree(id)","typeGuard":null,"tryCatchPattern":"bt := treenode.GetBlockTree(id)\nif bt == nil {\n    // GetBlockTree swallows errBlockTreeDBUnavailable; treat nil during boot as fatal\n    if !booted { return fmt.Errorf(\"blocktree db not yet initialised\") }\n}","preventionTips":["Do not issue blocktree queries until the kernel Boot sequence has finished initDatabase.","If the kernel log shows LogFatalf with ExitCodeUnavailableDatabase, fix the DB before retrying.","Treat a silent nil from GetBlockTree during startup as an init-order bug, not a missing block."],"tags":["blocktree","database","initialization","sqlite","boot"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}