fix: Handle EquivalentSchemaRuleAlreadyExists errors in Neo4j driver

Fixes #1079

Neo4j 5.26+ throws EquivalentSchemaRuleAlreadyExists errors when
creating indices in parallel, even with IF NOT EXISTS clause.

This fix:
- Catches neo4j.exceptions.ClientError exceptions
- Checks for EquivalentSchemaRuleAlreadyExists error code
- Logs the occurrence as info instead of error
- Returns empty result to indicate success (index/constraint exists)

This prevents the MCP server from crashing on startup when multiple
CREATE INDEX IF NOT EXISTS queries run concurrently via semaphore_gather.

The solution follows the same pattern already implemented in the
FalkorDB driver for handling "already indexed" errors.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
supmo668 2025-11-23 19:21:55 -08:00
parent 582e093582
commit a65634c2e1

View file

@ -18,6 +18,7 @@ import logging
from collections.abc import Coroutine from collections.abc import Coroutine
from typing import Any from typing import Any
import neo4j.exceptions
from neo4j import AsyncGraphDatabase, EagerResult from neo4j import AsyncGraphDatabase, EagerResult
from typing_extensions import LiteralString from typing_extensions import LiteralString
@ -70,6 +71,15 @@ class Neo4jDriver(GraphDriver):
try: try:
result = await self.client.execute_query(cypher_query_, parameters_=params, **kwargs) result = await self.client.execute_query(cypher_query_, parameters_=params, **kwargs)
except neo4j.exceptions.ClientError as e:
# Handle race condition when creating indices/constraints in parallel
# Neo4j 5.26+ may throw EquivalentSchemaRuleAlreadyExists even with IF NOT EXISTS
if 'EquivalentSchemaRuleAlreadyExists' in str(e):
logger.info(f'Index or constraint already exists, continuing: {cypher_query_}')
# Return empty result to indicate success (index exists)
return EagerResult([], None, None) # type: ignore
logger.error(f'Error executing Neo4j query: {e}\n{cypher_query_}\n{params}')
raise
except Exception as e: except Exception as e:
logger.error(f'Error executing Neo4j query: {e}\n{cypher_query_}\n{params}') logger.error(f'Error executing Neo4j query: {e}\n{cypher_query_}\n{params}')
raise raise