From c701b02b83c6869515ae95a989b95f9dfd88a517 Mon Sep 17 00:00:00 2001 From: Daniel Hardman Date: Wed, 22 Jul 2026 13:45:05 -0600 Subject: [PATCH] fix: stop witness start double-opening the reg LMDB env MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `kli witness start` on this 1.3 line aborts at "Starting witness..." with `lmdb.Error: The environment '.../reg/witness' is already open in this process`. Two independent code paths open the same reg (credential registry) LMDB path in one process, which LMDB forbids: 1. QueryEnd.__init__ created its OWN `Reger(name=hab.name, …)` on the same reg path as setupWitness's shared reger. Fix: thread the shared reger into QueryEnd (QueryEnd(hab, reger)) and reuse it, exactly as keri main does. 2. LMDBer.reopen() called lmdb.open() without first closing an already-open env, so reopening the reg via its BaserDoer opened a second handle on the same path. Fix: close self.env (best-effort) and null it before re-opening, making reopen() idempotent — again matching keri main. Both are backports of the corresponding keri-main changes. With them the witness boots cleanly and the closure qualifies through the witness-qualifier bar. Co-Authored-By: Claude Opus 4.8 (1M context) Signed-off-by: Daniel Hardman --- src/keri/app/indirecting.py | 9 ++++++--- src/keri/db/dbing.py | 12 ++++++++++++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/keri/app/indirecting.py b/src/keri/app/indirecting.py index e2e1f8875..6c6556bec 100644 --- a/src/keri/app/indirecting.py +++ b/src/keri/app/indirecting.py @@ -93,7 +93,7 @@ def setupWitness(hby, alias="witness", mbx=None, aids=None, tcpPort=5631, httpPo app.add_route("/", httpEnd) receiptEnd = ReceiptEnd(hab=hab, inbound=cues, aids=aids) app.add_route("/receipts", receiptEnd) - queryEnd = QueryEnd(hab=hab) + queryEnd = QueryEnd(hab=hab, reger=reger) app.add_route("/query", queryEnd) metricsEnd = EscrowEnd(hby=hby, reger=reger) app.add_route("/metrics", metricsEnd) @@ -1202,9 +1202,12 @@ class QueryEnd: """ - def __init__(self, hab): + def __init__(self, hab, reger=None): self.hab = hab - self.reger = viring.Reger(name=hab.name, db=hab.db, temp=False) + # Reuse the witness's shared Reger rather than opening a SECOND LMDB env on the same + # reg path — two env handles for one path in a process raise LMDB's "already open in + # this process" and abort witness start (matches keri main, which threads the reger in). + self.reger = reger if reger is not None else viring.Reger(name=hab.name, db=hab.db, temp=False) def on_get(self, req, rep): """ Handles GET requests to query KEL or TEL events of a pre from a witness. diff --git a/src/keri/db/dbing.py b/src/keri/db/dbing.py index 5abfff213..44c2d6723 100644 --- a/src/keri/db/dbing.py +++ b/src/keri/db/dbing.py @@ -416,6 +416,18 @@ def reopen(self, readonly=False, **kwa): if readonly is not None: self.readonly = readonly + # close self.env if already open so reopen() is idempotent: LMDB raises + # "The environment '' is already open in this process" if the same + # path is opened twice in one process. The witness start path opens the + # reg env at Reger construction and again via its BaserDoer, so without + # this close-first the witness aborts at "Starting witness...". + if self.env: + try: + self.env.close() + except: # noqa: E722 - best-effort close before reopen (matches keri main) + pass + + self.env = None # open lmdb major database instance # creates files data.mdb and lock.mdb in .dbDirPath self.env = lmdb.open(self.path, max_dbs=self.MaxNamedDBs, map_size=self.MapSize,