Summary
libra init fails with fatal: failed to read config 'init.defaultBranch': ... no such table: config when the database at ~/.libra/libra.db is missing the legacy config table. The failure is triggered by the legacy-table fallback in the config cascade reader, and the printed hint (libra config --global init.defaultBranch <name>) cannot fix the problem because it writes to a different database (~/.libra/config.db), while init fails earlier in the local-scope read.
Environment
- libra 0.22.15 (installed at
~/.libra/bin/libra)
- macOS 26 (darwin 25.6.0), arm64
Steps to reproduce
- Have a
~/.libra/libra.db that was created at some point without the legacy config table (all other tables present and fully migrated; see evidence below).
- From
$HOME (or any non-repo directory under it), run:
Actual output
fatal: failed to read config 'init.defaultBranch': failed to query legacy config for 'init.defaultBranch' from database '/Users/eli/.libra/libra.db': Query Error: error returned from database: (code: 1) no such table: config: error returned from database: (code: 1) no such table: config
Hint: fix or remove the unreadable config with 'libra config --global init.defaultBranch <name>'
Running the suggested libra config --global init.defaultBranch main succeeds (verified: the row lands in ~/.libra/config.db), but re-running libra init still fails with the identical error.
Root cause
resolve_initial_branch_name (src/command/init.rs:504) reads init.defaultBranch via read_cascaded_config_value_strict(LocalIdentityTarget::CurrentRepo, ...), which resolves scopes in order: local repo → global → system.
- Repository discovery (
try_get_paths_full, src/utils/util.rs:625 + is_valid_storage_dir, src/utils/util.rs:160) walks up from cwd and accepts any directory containing a .libra/ that merely contains libra.db. The global libra home ~/.libra/ happens to contain libra.db, so from $HOME (or any non-repo subdirectory of it) the local config DB resolves to /Users/eli/.libra/libra.db.
read_config_entry_from_db_path_case_insensitive (src/internal/config.rs:1896) queries config_kv first (table exists, no matching row), then falls back to the legacy config table. That table is missing from this DB, so the SQLite query errors out instead of being treated as "no legacy rows".
- In
read_cascaded_config_value_strict (src/internal/config.rs:1371), local-scope errors propagate via ? — only the system scope is unconditionally skipped, and the global scope is skipped only for future-schema DBs (skip_global_scope_if_schema_future). So init hard-fails before the (healthy) global scope is ever consulted.
- The schema self-heal path
apply_database_schema_upgrades (src/internal/db.rs:766) tops up config_kv, the AI projection tables, the operation tables, and runs the versioned migrations — but there is no ensure_config_schema equivalent for the legacy config table, so a DB missing only that table never recovers on open.
Additionally, global_config_path() (src/internal/config.rs:1257) points at ~/.libra/config.db, which is why the error hint's suggested command writes to a different file and can never fix this failure — the hint is misleading.
Evidence from the affected machine (read-only inspection)
~/.libra/libra.db:
- Has
config_kv, object_index, schema_versions (migrated up to 2026082401), AI/operation/agent tables — no config table.
config_kv has 0 rows; reference, reflog, object_index, agent_session, ai_thread all have 0 rows (the file is effectively an empty artifact of the home directory being adopted as a repo storage).
~/.libra/config.db (the actual global config DB):
- Healthy: contains both
config and config_kv, and after running the hinted command it correctly holds init.defaultBranch = main — yet init still fails, confirming the failure happens in the local scope.
Suggested fixes
- In
read_config_entry_from_db_path_case_insensitive, treat a missing legacy config table as "no legacy rows" (e.g. probe with sqlite_schema_contains first, or map the no such table error to Ok(None)), matching the tolerant posture of the system scope.
- Add an
ensure_config_schema step (analogous to ensure_config_kv_schema) to apply_database_schema_upgrades so DBs missing only the legacy table self-heal on open.
- Fix the
InitError::ConfigRead hint: in this scenario libra config --global ... targets ~/.libra/config.db and cannot repair a broken ~/.libra/libra.db.
- Design question worth considering:
~/.libra (the global home: config.db, vault-keys/, bin/, …) currently satisfies is_valid_storage_dir because it contains libra.db, so any command run from $HOME without a nearer repository resolves the home as the enclosing repo and reads ~/.libra/libra.db as "local" config. Excluding the global home directory from repository discovery would prevent this whole class of accidents.
Workaround
Recreate the missing table with the canonical bootstrap schema (additive, no data risk):
sqlite3 ~/.libra/libra.db "CREATE TABLE IF NOT EXISTS config (
id INTEGER PRIMARY KEY AUTOINCREMENT,
configuration TEXT NOT NULL,
name TEXT,
key TEXT NOT NULL,
value TEXT NOT NULL
);"
Alternatively, libra init linked -b main bypasses the config read for init only — but other commands that read other keys through the same DB will keep hitting the same error.
Summary
libra initfails withfatal: failed to read config 'init.defaultBranch': ... no such table: configwhen the database at~/.libra/libra.dbis missing the legacyconfigtable. The failure is triggered by the legacy-table fallback in the config cascade reader, and the printed hint (libra config --global init.defaultBranch <name>) cannot fix the problem because it writes to a different database (~/.libra/config.db), while init fails earlier in the local-scope read.Environment
~/.libra/bin/libra)Steps to reproduce
~/.libra/libra.dbthat was created at some point without the legacyconfigtable (all other tables present and fully migrated; see evidence below).$HOME(or any non-repo directory under it), run:$ libra init linkedActual output
Running the suggested
libra config --global init.defaultBranch mainsucceeds (verified: the row lands in~/.libra/config.db), but re-runninglibra initstill fails with the identical error.Root cause
resolve_initial_branch_name(src/command/init.rs:504) readsinit.defaultBranchviaread_cascaded_config_value_strict(LocalIdentityTarget::CurrentRepo, ...), which resolves scopes in order: local repo → global → system.try_get_paths_full,src/utils/util.rs:625+is_valid_storage_dir,src/utils/util.rs:160) walks up from cwd and accepts any directory containing a.libra/that merely containslibra.db. The global libra home~/.libra/happens to containlibra.db, so from$HOME(or any non-repo subdirectory of it) the local config DB resolves to/Users/eli/.libra/libra.db.read_config_entry_from_db_path_case_insensitive(src/internal/config.rs:1896) queriesconfig_kvfirst (table exists, no matching row), then falls back to the legacyconfigtable. That table is missing from this DB, so the SQLite query errors out instead of being treated as "no legacy rows".read_cascaded_config_value_strict(src/internal/config.rs:1371), local-scope errors propagate via?— only the system scope is unconditionally skipped, and the global scope is skipped only for future-schema DBs (skip_global_scope_if_schema_future). So init hard-fails before the (healthy) global scope is ever consulted.apply_database_schema_upgrades(src/internal/db.rs:766) tops upconfig_kv, the AI projection tables, the operation tables, and runs the versioned migrations — but there is noensure_config_schemaequivalent for the legacyconfigtable, so a DB missing only that table never recovers on open.Additionally,
global_config_path()(src/internal/config.rs:1257) points at~/.libra/config.db, which is why the error hint's suggested command writes to a different file and can never fix this failure — the hint is misleading.Evidence from the affected machine (read-only inspection)
~/.libra/libra.db:config_kv,object_index,schema_versions(migrated up to2026082401), AI/operation/agent tables — noconfigtable.config_kvhas 0 rows;reference,reflog,object_index,agent_session,ai_threadall have 0 rows (the file is effectively an empty artifact of the home directory being adopted as a repo storage).~/.libra/config.db(the actual global config DB):configandconfig_kv, and after running the hinted command it correctly holdsinit.defaultBranch = main— yet init still fails, confirming the failure happens in the local scope.Suggested fixes
read_config_entry_from_db_path_case_insensitive, treat a missing legacyconfigtable as "no legacy rows" (e.g. probe withsqlite_schema_containsfirst, or map theno such tableerror toOk(None)), matching the tolerant posture of the system scope.ensure_config_schemastep (analogous toensure_config_kv_schema) toapply_database_schema_upgradesso DBs missing only the legacy table self-heal on open.InitError::ConfigReadhint: in this scenariolibra config --global ...targets~/.libra/config.dband cannot repair a broken~/.libra/libra.db.~/.libra(the global home:config.db,vault-keys/,bin/, …) currently satisfiesis_valid_storage_dirbecause it containslibra.db, so any command run from$HOMEwithout a nearer repository resolves the home as the enclosing repo and reads~/.libra/libra.dbas "local" config. Excluding the global home directory from repository discovery would prevent this whole class of accidents.Workaround
Recreate the missing table with the canonical bootstrap schema (additive, no data risk):
Alternatively,
libra init linked -b mainbypasses the config read for init only — but other commands that read other keys through the same DB will keep hitting the same error.