Skip to content

[4.0.0-beta desktop] CBL_AVAILABLE is True even when Couchbase Lite bindings are missing #248

Closed

Description

@Fujio-Turner

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 = False

cbl_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_AVAILABLE is True
  • storage() skips the "not available" branch
  • CBLStore() raises RuntimeError ("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_store

Keep /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

  1. Fujio-Turner commented on Sep 15, 2026

    @Fujio-Turner
    OwnerAuthor

    Fixed on release-4.0.0-beta via #263

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions