-
Notifications
You must be signed in to change notification settings - Fork 0
fix: handle Neo4j 5.x race condition during index creation #13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
## Summary - Wrap build_indices_and_constraints() with try/except in both entrypoints - Catch EquivalentSchemaRuleAlreadyExists error (Neo4j 5.x parallel index creation race condition) - Log warning and continue (indexes are created successfully despite error) - Add integration tests to verify error handling - Update CLAUDE.md troubleshooting documentation ## Changes - src/server.py: Add race condition error handling - src/graphiti_mcp_server.py: Add race condition error handling (legacy entrypoint) - tests/test_neo4j_race_condition.py: Integration tests for error handling - CLAUDE.md: Document the warning message in troubleshooting section ## Technical Details Neo4j 5.x has a known issue where concurrent CREATE INDEX ... IF NOT EXISTS statements can fail with EquivalentSchemaRuleAlreadyExists even though the guard clause should prevent this. The upstream graphiti_core library runs ~19 index creation queries in parallel via semaphore_gather(), triggering this race condition. The fix catches this specific error and continues execution, as the indexes are successfully created by whichever parallel query completes first. ## Testing - Integration tests verify graceful handling of race condition error - Integration tests verify other errors are properly re-raised - Manual testing with Neo4j 5.26.0 confirms server starts successfully - All existing tests pass ## References - Upstream PR: getzep/graphiti#1081 (comment) - Neo4j Issue: neo4j/neo4j#13208 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
Code Review: Neo4j 5.x Race Condition Fix✅ Overall AssessmentThis is a well-executed fix for a real production issue. The PR demonstrates good practices in error handling, testing, and documentation. The solution is pragmatic and appropriate for handling an upstream race condition. Detailed Review🎯 Code Quality: ExcellentStrengths:
Error Handling Pattern (src/server.py:157-168): try:
await self.client.build_indices_and_constraints()
except Exception as idx_error:
if 'EquivalentSchemaRuleAlreadyExists' in str(idx_error):
logger.warning(...)
else:
raiseThis is the right approach - catch broadly, filter specifically, re-raise everything else. 🐛 Potential Issues: Minor Improvements Suggested1. String-based Exception DetectionIssue: Using Recommendation: Consider checking for the actual Neo4j exception type: # More robust approach
try:
from neo4j.exceptions import ClientError
if isinstance(idx_error, ClientError) and 'EquivalentSchemaRuleAlreadyExists' in str(idx_error.code):
# handle race condition
except ImportError:
# Fallback to string checking if neo4j not installed
if 'EquivalentSchemaRuleAlreadyExists' in str(idx_error):
# handle race conditionHowever, given that this is an upstream Graphiti issue and the error comes wrapped through multiple layers, the current string-based approach is acceptable and pragmatic. Just document this tradeoff. 2. Test SpecificityIssue: Tests use generic Current (test_neo4j_race_condition.py:31): mock_error = Exception('Neo.ClientError.Schema.EquivalentSchemaRuleAlreadyExists')Suggestion: Import and use real Neo4j exceptions for more realistic testing: try:
from neo4j.exceptions import ClientError
mock_error = ClientError.hydrate(
code='Neo.ClientError.Schema.EquivalentSchemaRuleAlreadyExists',
message='...'
)
except ImportError:
mock_error = Exception('Neo.ClientError.Schema.EquivalentSchemaRuleAlreadyExists')Note: This is a nice-to-have, not a blocker. Current tests are sufficient. ⚡ Performance Considerations: No Concerns
🔒 Security Concerns: None
🧪 Test Coverage: GoodCoverage:
Test Marker Usage: @pytest.mark.integration
@pytest.mark.requires_neo4jAppropriate markers for test categorization. Minor suggestion: Consider adding a test that verifies the service continues to function normally after handling the race condition (e.g., verify a subsequent operation succeeds). 📚 Documentation: ExcellentCLAUDE.md update (lines 599-609):
🎯 Best Practices AlignmentChecking against CLAUDE.md guidelines:
📋 RecommendationsPriority: Optional ImprovementsNone of these block the PR - they're enhancements for future consideration:
✅ Approval DecisionAPPROVED - Ready to MergeThis PR:
The minor suggestions above are optional enhancements that don't block merging. 🎉 Positive Highlights
Great work on this fix! 🚀 |
Summary
Fixes a race condition that causes the Graphiti MCP server to crash on startup when using Neo4j 5.x as the database backend.
Problem Description
Error:
Neo.ClientError.Schema.EquivalentSchemaRuleAlreadyExistsRoot Cause: Neo4j 5.x has a known issue where concurrent
CREATE INDEX ... IF NOT EXISTSstatements can fail even with the guard clause. The upstreamgraphiti_corelibrary runs ~19 index creation queries in parallel viasemaphore_gather(), triggering this race condition.Impact: MCP server crashes during initialization, making Neo4j 5.x deployments non-functional.
Solution
Wrap
build_indices_and_constraints()calls with try/except to catch and gracefully handle theEquivalentSchemaRuleAlreadyExistserror. The indexes are successfully created by whichever parallel query completes first, so we can safely continue execution.Changes
src/server.py: Add race condition error handling (production entrypoint)src/graphiti_mcp_server.py: Add race condition error handling (legacy entrypoint)tests/test_neo4j_race_condition.py: Integration tests for error handlingCLAUDE.md: Document the warning message in troubleshooting sectionTesting
Before Fix:
$ docker compose -f docker/docker-compose-neo4j.yml up -d # Container exits with code 1 neo4j.exceptions.ClientError: {neo4j_code: Neo.ClientError.Schema.EquivalentSchemaRuleAlreadyExists}After Fix:
Integration Tests:
References
Checklist
🤖 Generated with Claude Code