Repository navigation
[4.0.0-beta desktop] CBL_AVAILABLE is True even when Couchbase Lite bindings are missing #248
Description
PROBLEM
app.py decides whether storage is usable like this:
try:
from cbl_store import CBLStore, USE_CBL
CBL_AVAILABLE = True # always True if the .py file imported
except ImportError as e:
CBL_AVAILABLE = False
USE_CBL = Falsecbl_store.py always imports — it catches a missing CouchbaseLite package internally and sets USE_CBL = False. So on a desktop binary that has cbl_store.py but no bindings:
CBL_AVAILABLEisTruestorage()skips the "not available" branchCBLStore()raisesRuntimeError("CBLStore requires CBL bindings…")/api/storage/info, save analyzer, preferences, import/export become unhandled 500s instead of a clean JSON error
Docker healthchecks hit /api/storage/info. Desktop Settings calls the same endpoint on load (app/assets/js/settings.js).
Suggested RCA
The try/except ImportError is checking the wrong thing. The module is present; the native bindings are not. cbl_store.USE_CBL is already the real flag, but app.py ignores it when the import succeeds.
storage() also does not catch RuntimeError from CBLStore.__init__.
Suggested FIX
# app.py
try:
from cbl_store import CBLStore, USE_CBL
CBL_AVAILABLE = bool(USE_CBL)
except ImportError as e:
CBLStore = None # type: ignore
CBL_AVAILABLE = False
USE_CBL = False
logger.warning("cbl store unavailable: %s", e)
def storage():
global _cbl_store
if not CBL_AVAILABLE or CBLStore is None:
return None
if _cbl_store is None:
try:
_cbl_store = CBLStore()
logger.info("cbl storage initialized")
except Exception:
logger.exception("cbl storage failed to initialize")
return None
return _cbl_storeKeep /api/storage/info returning {'success': False, 'error': 'CBL not available'} with HTTP 503 (not 500) when storage() is None, so the UI can show a real message instead of a traceback.
Unit tests
These must run without CBL bindings (the current test_cbl_store.py is skipif(not USE_CBL)).
# tests/python/test_cbl_availability.py
import importlib
from unittest.mock import patch
import pytest
def test_cbl_available_follows_use_cbl_flag(monkeypatch):
import cbl_store
monkeypatch.setattr(cbl_store, "USE_CBL", False)
import app
importlib.reload(app)
assert app.CBL_AVAILABLE is False
def test_storage_returns_none_when_bindings_missing(monkeypatch):
import app
monkeypatch.setattr(app, "CBL_AVAILABLE", True)
class Boom:
def __init__(self):
raise RuntimeError("CBLStore requires CBL bindings (import error: fake)")
monkeypatch.setattr(app, "CBLStore", Boom)
monkeypatch.setattr(app, "_cbl_store", None)
assert app.storage() is None
def test_storage_info_is_json_error_not_traceback(client, monkeypatch):
import app
monkeypatch.setattr(app, "storage", lambda: None)
res = client.get("/api/storage/info")
assert res.status_code in (503, 500)
body = res.get_json()
assert body["success"] is False
assert "CBL" in body["error"]Reuse the Flask client fixture from tests/python/test_app_flask.py.
Context: found on branch release-4.0.0-beta while reviewing standalone macOS .app / Windows .exe packaging. Issues in this batch share the title prefix [4.0.0-beta desktop].
Activity
Fujio-Turner commentedon Sep 15, 2026
Fixed on
release-4.0.0-betavia #263