Repository navigation
fix(servers): data-unavailable error for every DB tool, no DB names - #601
Merged
Merged
Conversation
couchdb3.Database is falsy when its database does not exist (__bool__ sends a HEAD request), so the `if not iot_db` / `if not fm_db` guards fired before the missing-database message from #554 and returned "IoT records database not connected" / "database not connected". With CouchDB unreachable, __bool__ raised instead. Tool guards now go through _missing_db_error (FMSR: check()), helpers test `is None`, and an unknown site is checked against a missing asset registry first, since the registry falls back to ["MAIN"] when it cannot be read. Signed-off-by: Shuxin Lin <linshuhsin@gmail.com>
DhavalRepo18
approved these changes
Oct 2, 2026
Audited every CouchDB-backed MCP tool against a server with no databases and an unreachable server. Gaps fixed: - servers/db_errors.py: shared DATA_UNAVAILABLE message, and db_failure_text, which drops the URL/host/database name that HTTP client exceptions carry. - iot: sites() reports a missing registry instead of falling back to MAIN; exception paths no longer pass raw client text through. - wo: connection errors raise DatabaseUnavailable (was "All connection attempts failed"); HTTP errors no longer embed the request URL; get_failure_codes returns the shared message when the DB is unavailable. - vibration: truthiness on couchdb3.Database sent a request and raised when CouchDB was down, leaking the host; use `is None`. - utilities: catalog tools return the shared message instead of CouchDB's raw error body or a connection error with the host. - fmsr: shared message; lookup failures no longer include client exception text. Signed-off-by: Shuxin Lin <linshuhsin@gmail.com>
…able
CouchStore returned None/[] for a 404 on a missing database, so a catalog that
was never loaded read as empty ("model 'x' not found", "models": []), and with
CouchDB down every catalog/run tool returned a requests error that named the
collection, host and port.
CouchStore requests now raise StoreUnavailable when the server is unreachable
and StoreError without the URL on HTTP errors. Model and feature catalog reads
and registrations check the catalog exists first (Store.exists). Result and run
collections are still created on first write, so missing ones read as empty.
Signed-off-by: Shuxin Lin <linshuhsin@gmail.com>
HTTP errors are now CouchError (without the URL), so next_wonum's `except CouchError: continue` would retry a 500/401 or an unavailable database five times and report counter contention. Conflicts raise CouchConflict, and only those are retried. Signed-off-by: Shuxin Lin <linshuhsin@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Follow-up to #554. The missing-database message from #554 was hidden in IoT/FMSR by older
if not dbchecks, and several other servers never used it. I audited every MCP tool backed by CouchDB (85 tools, 6 servers). In each case the tool was run against (a) a CouchDB with no databases, (b) an unreachable CouchDB, and (c) databases that exist but are empty. The test databases had sentinel names, so any leaked name would show up.Every DB-touching tool now returns the shared message when its database is missing or unreachable:
No error contains a database name, host, port or URL. Wrong-key messages (
unknown site,No sensors found…,model 'x' not found, …) are unchanged when the database exists.Fix Details
servers/db_errors.py(new):DATA_UNAVAILABLE, plusdb_failure_text(exc), which replaces requests/httpx exception text (it embeds the URL, and so the DB name) withdatabase request failed (<ExcType>).couchdb3.Database.__bool__sends a HEAD request, soif not iot_dbfired before the missing-DB path ("IoT records database not connected"), and it raisedConnectionErrorwith the URL when CouchDB was down. The tool guards now use_missing_db_error, and helpers checkis None.unknown siteis checked against a missing registry first, because the registry falls back to["MAIN"].sites()reports a missing registry instead of returning["MAIN"].if not fm_dbissue. Lookup failures no longer include client exception text.DatabaseUnavailable. HTTP errors no longer embed the request URL (database request failed (HTTP 500)).get_failure_codesreturns the shared message when the database is unavailable.next_wonumnow retries only onCouchConflict(409), so HTTP errors aren't reported as counter contention.if not dbraised with the host when CouchDB was down. It now checksis None.CouchStoretreated a 404 for a missing database as a missing document. A catalog that was never loaded therefore read as empty ("models": [],model 'x' not found), and with CouchDB down every catalog and run tool leaked/<catalog_db>/_findplus the host. Requests now raiseStoreUnavailableorStoreErrorwithout the URL. Model and feature catalog reads and registrations check that the catalog exists (Store.exists). Result and run collections are still created on first write, so a missing one still means "none yet".Wire note:
sites()now returnsUnion[SitesResult, ErrorResult], the same as every other IoT tool. Its text content is unchanged. ItsstructuredContentis now wrapped in{"result": …}like the other tools. No caller in the repo reads the flat shape.Impact on Benchmarking
Related Issues
Verification Steps
uv run pytest src/ -q -k "not integration": 696 passed. The 8 failures left (evaluation/test_static_json_scorer.py,observability/test_file_exporter.py) also fail onmain.main, the IoT regression tests fail withIoT records database not connected/unknown site SITE_A.Checklist