Skip to content

Python: Cosmos NoSQL collection_exists reports a throttled request as a missing container - #14515

Open
Eric Del Orefice (ericdelorefice) wants to merge 2 commits into
microsoft:mainfrom
ericdelorefice:cosmos-collection-exists
Open

Eric Del Orefice (ericdelorefice) wants to merge 2 commits into
microsoft:mainfrom
ericdelorefice:cosmos-collection-exists

Conversation

@ericdelorefice

Copy link
Copy Markdown

Motivation and Context

CosmosNoSqlCollection.collection_exists catches CosmosHttpResponseError and returns False. That is the parent class of every Cosmos HTTP error, so a 401, a 403, a 429 or a 5xx all report that the container does not exist. Cosmos throttles with 429 routinely, so this is not only a theoretical case.

The same connector already answers the equivalent question for the database correctly:

async def _does_database_exist(self) -> bool:
    try:
        await self.cosmos_client.get_database_client(self.database_name).read()
        return True
    except CosmosResourceNotFoundError:
        return False
    except Exception as e:
        raise VectorStoreOperationException(...) from e

collection_exists makes the same call against the container, with a broader catch and no second branch.

I flagged this in #14510, which makes the same change for the Chroma connector.

Description

collection_exists now mirrors _does_database_exist: CosmosResourceNotFoundError returns False, and anything else is raised as VectorStoreOperationException with the container name in the message. CosmosResourceNotFoundError was already imported in this file.

One thing worth knowing, outside this change: VectorStore.collection_exists in data/vector.py wraps this method and converts a VectorStoreOperationException to False. So at the store level a failure still reads as absent. That is the framework wrapper's own choice, and I have left it alone here.

Contribution Checklist

Three unit tests, none existed for collection_exists on this collection. A missing container returns False, a 429 raises, and a successful read returns True.

Against unmodified main the 429 test fails and the other two pass, so the change cannot turn a missing container or a present one into an error.

30 passed                   # test_azure_cosmos_db_no_sql_collection.py
All checks passed!          # ruff check
2 files already formatted   # ruff format --check

… a missing container

collection_exists caught CosmosHttpResponseError and returned False. That
is the parent of every Cosmos HTTP error, so a 401, 403, 429 or 5xx all
reported that the container does not exist.

_does_database_exist in the same connector already answers the
equivalent question correctly: CosmosResourceNotFoundError returns False
and anything else raises VectorStoreOperationException.
collection_exists now mirrors it.

Three tests, none existed for collection_exists on this collection. A
missing container returns False, a 429 raises, a successful read returns
True. Against main only the 429 test fails.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟢 Approval recommended

The focused implementation matches the existing database behavior and covers the relevant outcomes.

Review effort: Balanced
Findings: None

What changed in this PR

Narrows Cosmos NoSQL existence handling so only missing containers return False.

Changes:

  • Wraps throttling and other failures in VectorStoreOperationException.
  • Adds tests for missing, throttled, and successful reads.
File Description
python/​semantic_kernel/​connectors/​azure_cosmos_db.py Corrects container existence error handling.
python/​tests/​unit/​connectors/​memory/​azure_cosmos_db/​test_azure_cosmos_db_no_sql_collection.py Tests the corrected behavior.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a community review and does not clear the merge gate. I ran this on Windows against upstream main at 64005c7, with azure-cosmos 4.17.1.

The change is right. CosmosResourceNotFoundError is a subclass of CosmosHttpResponseError (I checked), so the old except CosmosHttpResponseError: return False did turn a 429, 401, 403 or 5xx into "container does not exist", and the new code only does that for a 404. It also matches the abstract docstring in data/vector.py, which asks implementations to raise relevant exceptions with good descriptions.

What I ran:

  • The test file on the branch: all pass, including the three new collection_exists tests.
  • The same test file against main's source: only test_azure_cosmos_db_no_sql_collection_exists_raises_on_a_throttled_request fails. The other two new tests pass on main as well, since they describe behavior main already had, so they are only guards.

Two things I hit that this PR does not change, so they are context and not requests. I used a mocked CosmosClient here, not a live account:

  1. collection_exists calls _get_container_proxy before the try, and that goes through _get_database_proxy. With the database missing and create_database=False, collection_exists() raises VectorStoreOperationException("Failed to get container proxy for 'c'.") and does not return False. So "false when the container is missing" only holds when the database exists.
  2. With the database missing and create_database=True, the same call creates the database (create_database was awaited once in my probe). A pure existence check with a write side effect is surprising, though it predates this PR.

The PR text already notes that VectorStore.collection_exists turns VectorStoreOperationException into False. I read that wrapper at data/vector.py lines 1576 to 1587 and agree: at the store level, a throttled container still reads as absent after this change. The collection-level fix still matters, since CosmosNoSqlCollection.collection_exists is the public method on the collection.

Small test note: the three new tests mock _get_container_proxy, so none of them exercises the path in point 1.

Eric Del Orefice (ericdelorefice) added a commit to ericdelorefice/semantic-kernel that referenced this pull request Oct 7, 2026
The connector only imports on chromadb 1.x (it needs
chromadb.api.collection_configuration), so the ValueError fallback for
chromadb < 1.0 could never run; it is removed, with the two tests it gated.

collection_exists now wraps any other error in VectorStoreOperationException,
matching ensure_collection_deleted here and the Cosmos NoSQL change in microsoft#14515.
@ericdelorefice

Copy link
Copy Markdown
Author

Thank you for running this against main and checking the exception hierarchy. That was the part I most wanted someone else to look at.

You're right that both of your notes predate this PR, so I've kept it to the one change. The first is real: with the database missing and create_database=False, collection_exists raises instead of returning False, and none of the new tests reach that path because they mock _get_container_proxy. The second, an existence check that can create the database, is a design question for the maintainers. If they would like it, I'll open an issue for the first.

Agreed on the store level too. VectorStore.collection_exists in data/vector.py still turns VectorStoreOperationException into False, so a throttled container still reads as absent there. That wrapper is shared by every connector, so I'd rather raise it with the maintainers than change it inside this PR. I've made #14510 wrap its errors the same way this one does, so the two connectors now behave alike.

🤖 Addressed by Claude Code

This branch was previously deployed

1 inactive deployment
github-app-auth — cb72bed4 Deployed Sep 30, 2026 by ericdelorefice via add_label #29199
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

python Pull requests for the Python Semantic Kernel

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants