mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-08 03:08:45 +00:00
fix(vector_stores): name the connection string when Atlas rejects MongoDB credentials
Atlas answers a wrong password with code 8000 "AtlasError" rather than the 18 a self-hosted deployment returns, so the code-only check never fired and a bad password came back as a generic "MongoDB rejected the vector search", pointing the reader at the index instead of at their credentials. Verified live against Atlas with a tampered password.
This commit is contained in:
parent
8374b34b81
commit
85431297b9
2 changed files with 34 additions and 2 deletions
|
|
@ -110,6 +110,9 @@ def reset_client_cache() -> None:
|
|||
|
||||
_AUTHENTICATION_FAILED_CODE: Final = 18
|
||||
_UNAUTHORIZED_CODE: Final = 13
|
||||
# Atlas reports a rejected user as code 8000 "AtlasError" rather than 18, so the
|
||||
# message is the only reliable signal for a serverless or shared-tier deployment.
|
||||
_AUTHENTICATION_MESSAGE_MARKERS: Final = ("bad auth", "authentication failed", "not authorized")
|
||||
|
||||
|
||||
def _index_hint(index_name: str, database: str, collection: str) -> str:
|
||||
|
|
@ -169,12 +172,14 @@ def translate_mongo_error(error: Exception, index_name: str, database: str, coll
|
|||
)
|
||||
if isinstance(error, OperationFailure):
|
||||
code: Final = error.code
|
||||
if code in (_AUTHENTICATION_FAILED_CODE, _UNAUTHORIZED_CODE):
|
||||
detail: Final = str(error).lower()
|
||||
if code in (_AUTHENTICATION_FAILED_CODE, _UNAUTHORIZED_CODE) or any(
|
||||
marker in detail for marker in _AUTHENTICATION_MESSAGE_MARKERS
|
||||
):
|
||||
return config_error(
|
||||
"MongoDB rejected the credentials in mongodb_connection_string, or the database user "
|
||||
f"lacks read access to '{database}.{collection}'. Driver detail: {error.details}"
|
||||
)
|
||||
detail: Final = str(error).lower()
|
||||
if "dimension" in detail:
|
||||
return config_error(
|
||||
"The query embedding does not match the vector dimensions the Atlas index was built for. "
|
||||
|
|
|
|||
|
|
@ -860,3 +860,30 @@ class TestErrorsCarryTheRightHttpStatus:
|
|||
translate_mongo_error(original, index_name="idx", database="db", collection="coll")
|
||||
is original
|
||||
)
|
||||
|
||||
|
||||
def test_atlas_rejected_credentials_are_named_even_though_the_code_is_8000():
|
||||
"""Atlas answers a wrong password with code 8000 "AtlasError", not the 18 that a
|
||||
self-hosted deployment returns, so a code-only check reports it as a generic
|
||||
rejected search and never tells the caller to look at their connection string."""
|
||||
from pymongo.errors import OperationFailure
|
||||
|
||||
error = OperationFailure(
|
||||
"bad auth : authentication failed",
|
||||
code=8000,
|
||||
details={"ok": 0, "errmsg": "bad auth : authentication failed", "code": 8000, "codeName": "AtlasError"},
|
||||
)
|
||||
translated = translate_mongo_error(error, index_name="idx", database="sample_mflix", collection="embedded_movies")
|
||||
|
||||
assert isinstance(translated, BadRequestError)
|
||||
assert "mongodb_connection_string" in str(translated)
|
||||
assert "sample_mflix.embedded_movies" in str(translated)
|
||||
|
||||
|
||||
def test_a_rejected_search_that_is_not_an_auth_failure_keeps_the_generic_message():
|
||||
from pymongo.errors import OperationFailure
|
||||
|
||||
error = OperationFailure("PlanExecutor error", code=8, details={"errmsg": "PlanExecutor error"})
|
||||
translated = translate_mongo_error(error, index_name="idx", database="db", collection="coll")
|
||||
|
||||
assert "mongodb_connection_string" not in str(translated)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue