đź”§ Troubleshooting Guide
This guide helps you diagnose and resolve common issues when working with CVOYA graph.
🚨 Common Issues and Solutions
Connection Issues
Problem: “Unable to connect to Neo4j database”
Neo4jException: Could not perform discovery for server neo4j://localhost:7687
Solutions:
-
Check Neo4j is running
# For Neo4j Desktop - ensure database is started # For Docker: docker ps | grep neo4j # Start Neo4j with Docker if not running: docker run --name neo4j -p 7474:7474 -p 7687:7687 -e NEO4J_AUTH=neo4j/password neo4j:latest -
Verify connection string format
// ✅ Correct formats: var local = "neo4j://localhost:7687"; // Local unencrypted var encrypted = "neo4j+s://your-server:7687"; // Remote encrypted var selfSigned = "neo4j+ssc://your-server:7687"; // Encrypted with self-signed cert // ❌ Common mistakes: var missingPort = "neo4j://localhost"; // Missing port var wrongProtocol = "http://localhost:7474"; // Wrong protocol (that's HTTP interface) -
Check credentials
// Default Neo4j credentials are neo4j/neo4j // You must change the password on first login var store = new Neo4jGraphStore("neo4j://localhost:7687", "neo4j", "your-new-password"); var graph = store.Graph;
Problem: “Connection timeout”
TimeoutException: The request timed out after 30 seconds
Solutions:
-
Increase timeout settings
var driver = GraphDatabase.Driver( connectionString, AuthTokens.Basic(username, password), config => config .WithConnectionTimeout(TimeSpan.FromSeconds(60)) .WithConnectionAcquisitionTimeout(TimeSpan.FromSeconds(60))); var store = new Neo4jGraphStore(driver); var graph = store.Graph; -
Check network connectivity
telnet your-server 7687 # Should connect if Neo4j is accessible
Query Issues
Problem: “No nodes found” when you expect results
var users = await graph.Nodes<User>().ToListAsync();
// Returns empty list when you expect data
Debugging steps:
-
Check node labels in database
// In Neo4j Browser: MATCH (n) RETURN DISTINCT labels(n) -
Verify entity class labels
[Node("User")] // Must match label in database public record User : Node { } -
Check case sensitivity
[Node("user")] public record LowercaseUser : Node; [Node("User")] public record User : Node; // Different label from "user" -
Enable query logging
using var loggerFactory = LoggerFactory.Create(builder => builder.AddConsole()); var neo4jGraphStore = new Neo4jGraphStore( "neo4j://localhost:7687", "neo4j", "password", loggerFactory: loggerFactory);
Problem: “Invalid cast” when querying
InvalidCastException: Unable to cast object of type 'System.String' to type 'System.Int32'
Solutions:
-
Check property types match database
// If database has string IDs but your model expects int: public class User : INode { // CG011 warns on direct INode implementations; inherit from Node unless you need full control. public string Id { get; init; } = Guid.NewGuid().ToString(); // Use string if Neo4j stores as string public IReadOnlyList<string> Labels { get; } = Array.Empty<string>(); // Not: public int Id { get; set; } } -
Use nullable types for optional properties
public class User : INode { // CG011 warns on direct INode implementations; inherit from Node unless you need full control. public string Id { get; init; } = Guid.NewGuid().ToString(); public IReadOnlyList<string> Labels { get; } = Array.Empty<string>(); public int? Age { get; set; } // Nullable if not always present public DateTime? CreatedDate { get; set; } // Nullable for optional dates }
Transaction Issues
Problem: “Transaction already committed/rolled back”
InvalidOperationException: Cannot execute query on committed/rolled back transaction
Solution:
var user = new User { Email = "one@example.com" };
var anotherUser = new User { Email = "two@example.com" };
// ❌ Reusing disposed transaction
await using var completedTransaction = await graph.GetTransactionAsync();
await graph.CreateNodeAsync(user, completedTransaction);
await completedTransaction.CommitAsync();
await graph.CreateNodeAsync(anotherUser, completedTransaction); // Error - transaction already committed
// âś… Create new transaction or don't commit until all operations complete
await using var transaction = await graph.GetTransactionAsync();
await graph.CreateNodeAsync(user, transaction);
await graph.CreateNodeAsync(anotherUser, transaction);
await transaction.CommitAsync(); // Commit both operations
Problem: “Deadlock detected”
TransientException: Deadlock detected
Solutions:
-
Keep transactions short
// ✅ Short transaction await using var shortTransaction = await graph.GetTransactionAsync(); await graph.CreateNodeAsync(user, shortTransaction); await shortTransaction.CommitAsync(); // ❌ Long-running transaction await using var longTransaction = await graph.GetTransactionAsync(); await SomeLongRunningOperation(); // Holds locks too long await graph.CreateNodeAsync(user, longTransaction); await longTransaction.CommitAsync(); -
Retry logic for deadlocks
public async Task<T> ExecuteWithRetry<T>(Func<Task<T>> operation, int maxRetries = 3) { for (int attempt = 0; attempt < maxRetries; attempt++) { try { return await operation(); } catch (TransientException ex) when (ex.Message.Contains("Deadlock")) { if (attempt == maxRetries - 1) throw; await Task.Delay(TimeSpan.FromMilliseconds(100 * (attempt + 1))); } } throw new InvalidOperationException("Should not reach here"); }
Performance Issues
Problem: “Queries are very slow”
Debugging steps:
-
Enable query profiling
using var loggerFactory = LoggerFactory.Create(builder => builder.AddConsole()); var neo4jGraphStore = new Neo4jGraphStore( "neo4j://localhost:7687", "neo4j", "password", loggerFactory: loggerFactory); -
Look for full table scans
// Profile a slow query: PROFILE MATCH (u:User) WHERE u.email = 'test@example.com' RETURN u -
Check for unlimited traversals
// ❌ Large depth - could traverse a large path of the graph var largeConnections = await graph.Nodes<User>() .Traverse<FriendOf, User>(minDepth: 1, maxDepth: 100) .ToListAsync(); // ✅ Limited depth var limitedConnections = await graph.Nodes<User>() .Traverse<FriendOf, User>(minDepth: 1, maxDepth: 3) // Max 3 hops .ToListAsync();
Problem: “Out of memory” with large datasets
Solutions:
-
Use pagination
// ❌ Loading everything at once var allUsers = await graph.Nodes<User>().ToListAsync(); // ✅ Paginated loading var pageSize = 1000; var page = 0; List<User> batch; do { batch = await graph.Nodes<User>() .OrderBy(u => u.Id) .Skip(page * pageSize) .Take(pageSize) .ToListAsync(); ProcessBatch(batch); page++; } while (batch.Count == pageSize); -
Use streaming
// âś… Process one at a time
await foreach (var user in graph.Nodes<User>())
{
ProcessUser(user);
}
Analyzer Issues
Problem: Analyzer warnings in IDE
Understanding diagnostics:
| Rule ID | Description | Severity |
|---|---|---|
| CG001 | Missing parameterless constructor | Error |
| CG002 | Property must have public accessors | Error |
| CG003 | Property cannot be graph interface type | Error |
| CG004 | Invalid property type for node | Error |
| CG005 | Invalid property type for relationship | Error |
| CG006 | Complex type contains graph interface types | Error |
| CG007 | Duplicate property attribute label | Error |
| CG008 | Duplicate relationship attribute label | Error |
| CG009 | Duplicate node attribute label | Error |
| CG010 | Circular reference without nullable | Error |
| CG011 | Type should inherit from Node/Relationship instead of implementing directly | Warning |
| CG012 | [Node]/[Relationship] on a type that doesn’t implement the matching interface | Warning |
| CG013 | Both [Node] and [Relationship] applied to the same type | Error |
| CG014 | Graph entity types (INode/IRelationship) must be reference types | Error |
| CG015 | [ComplexProperty] has no effect on the configured property | Warning |
| CG016 | Open generic graph entities are not supported | Error |
| CG017 | Nullable complex collection elements are not supported | Error |
Solutions: See the Analyzers README for detailed examples of each warning and how to fix them.
🔍 Debugging Techniques
1. Enable Detailed Logging
using var loggerFactory = LoggerFactory.Create(builder => builder.AddConsole());
var neo4jGraphStore = new Neo4jGraphStore(
"neo4j://localhost:7687",
"neo4j",
"password",
loggerFactory: loggerFactory);
2. Inspect Generated Cypher
// The logger will show queries like:
// MATCH (n:User) WHERE n.email = $p1 RETURN n
// Parameters: p1 = "test@example.com"
3. Test Queries Directly in Neo4j Browser
- Copy the generated Cypher from logs
- Paste into Neo4j Browser (http://localhost:7474)
- Run with same parameters
- Use
PROFILEorEXPLAINto understand performance
4. Verify Database State
// Check what's actually in the database:
MATCH (n) RETURN labels(n), count(n) // Node counts by label
MATCH ()-[r]->() RETURN type(r), count(r) // Relationship counts by type
MATCH (n:User) RETURN n LIMIT 10 // Sample user nodes
5. Connection Testing
public async Task<bool> TestConnection(string connectionString, string username, string password)
{
try
{
await using var store = new Neo4jGraphStore(connectionString, username, password);
await store.Graph.Nodes<DynamicNode>().Take(1).ToListAsync();
return true;
}
catch (Exception ex)
{
Console.WriteLine($"Connection failed: {ex.Message}");
return false;
}
}
📞 Getting Help
1. Gather Information
When reporting issues, include:
- CVOYA graph version
- .NET version
- Neo4j version
- Full error message and stack trace
- Minimal code example that reproduces the issue
- Generated Cypher query (if applicable)
2. Check Documentation
3. Search Existing Issues
- Check GitHub Issues
- Look for similar problems and solutions
4. Create Minimal Reproduction
// Example minimal reproduction case:
public record TestNode : Node
{
public string Name { get; set; } = string.Empty;
}
// The issue occurs when:
public static class Reproduction
{
public static async Task ReproduceAsync()
{
await using var store = new Neo4jGraphStore("neo4j://localhost:7687", "neo4j", "password");
var graph = store.Graph;
var node = new TestNode { Id = "1", Name = "Test" };
await graph.CreateNodeAsync(node); // Fails here with [specific error]
}
}
Remember: The more specific and complete your issue report, the faster we can help! 🚀