Skip to content

Debugging and Troubleshooting Guide

This guide covers common issues you might encounter while developing LBS Foundry and how to resolve them.

Common Issues and Solutions

Build Issues

Compilation Errors

Symptoms: dotnet build fails with compilation errors

Solutions:

# 1. Clean and rebuild
dotnet clean LBS.slnx
dotnet build LBS.slnx

# 2. Restore dependencies
dotnet restore LBS.slnx

# 3. Check for missing dependencies
dotnet list package --outdated

Common Causes: - Missing NuGet packages - Version conflicts between packages - Syntax errors in recent changes - Missing using statements

Project Reference Issues

Symptoms: "Could not find project file" or assembly reference errors

Solutions:

# Verify project references
dotnet list LBS.slnx reference

# Re-add a problematic reference
dotnet remove reference path/to/project
dotnet add reference path/to/project

Database Issues

Connection Problems

Symptoms: "Cannot connect to database" or timeout errors

Diagnostics:

# Check PostgreSQL status
# Windows
net start postgresql

# macOS/Linux
brew services list | grep postgresql
systemctl status postgresql

# Test connection manually
psql -h localhost -U your_username -d lbs_foundry_dev

Solutions: 1. Check connection string in appsettings.json 2. Verify PostgreSQL is running 3. Check firewall settings 4. Validate credentials

Migration Issues

Symptoms: Database schema doesn't match expectations

Solutions:

# There is no separate migration step. Marten applies the schema automatically on
# application startup via ApplyAllDatabaseChangesOnStartup() (AutoCreate.All), so
# starting a host such as the API creates/updates the schema.
dotnet run --project src/Apps/LBS.Api/LBS.Api.csproj

# Reset database (development only), then start a host to re-apply the schema
dropdb lbs_foundry_dev
createdb lbs_foundry_dev
dotnet run --project src/Apps/LBS.Api/LBS.Api.csproj

Marten Projection Issues

Symptoms: Read models are empty or outdated

Diagnostics:

# Check projection status in database
SELECT name, lifecycle, last_seq_id FROM mt_event_progression;

Solutions:

# Schema objects are created automatically on host startup
# (ApplyAllDatabaseChangesOnStartup() / AutoCreate.All), and the async daemon
# (AddAsyncDaemon(DaemonMode.HotCold)) processes projections while a host runs.
dotnet run --project src/Apps/LBS.Api/LBS.Api.csproj

# To rebuild a projection, use Marten's projection rebuild API
# (IProjectionDaemon.RebuildProjectionAsync) from a host that has the event store
# configured, or drop and recreate the read-model schema and let it replay.

Frontend Issues

Node/pnpm Problems

Symptoms: Frontend won't start or has dependency issues

Solutions:

# Rebuild SDK (most common fix for foundry-web)
pnpm sdk:refresh

# Clear cache and reinstall (from repo root)
rm -rf node_modules sdk/typescript/node_modules src/Apps/foundry-web/node_modules
pnpm install
pnpm sdk:refresh

# Check Node version
node --version  # Should be 18+

Build Failures

Symptoms: pnpm build fails

Common Issues: - TypeScript compilation errors - Missing environment variables - Linting failures

Solutions:

# Check TypeScript errors
pnpm tsc --noEmit

# Fix linting issues
pnpm lint --fix

# Check environment variables
cat .env.local

API Connection Issues

Symptoms: Frontend can't connect to backend API

Diagnostics: 1. Check backend is running: Visit http://localhost:5000/swagger 2. Verify API URLs in frontend configuration 3. Check CORS settings in backend 4. Inspect browser network tab for error details

Solutions:

# Check API base URL in frontend
grep -r "baseUrl" src/Apps/foundry-web/src/

# Verify backend CORS configuration
# Check src/Apps/LBS.Api/Program.cs

Authentication Issues

JWT Token Problems

Symptoms: "Unauthorized" errors despite being logged in

Diagnostics:

// Add logging to ClerkAuthenticationHandler
public async Task<AuthenticateResult> HandleAuthenticateAsync()
{
    this.logger.LogDebug("Processing authentication request");
    // ... existing logic
}

Solutions: 1. Check Clerk configuration in appsettings.json 2. Verify JWT token format in browser dev tools 3. Check token expiration 4. Validate Clerk public key

Service Account Authentication

Symptoms: Basic auth failing for service accounts

Diagnostics:

# Test basic auth manually
curl -H "Authorization: Basic $(echo -n 'email:password' | base64)" \
     http://localhost:5000/api/readmodel

# Check user exists in database
psql -d lbs_foundry_dev -c "SELECT email, account_type FROM user_contracts WHERE email = 'service@example.com';"

Solutions: 1. Verify service account exists 2. Check password hash format 3. Validate basic auth header encoding

Event Sourcing Issues

Command Execution Failures

Symptoms: Commands throw exceptions or don't create events

Debugging Steps:

// Add detailed logging to aggregates
public void Execute(CreatePlayerCommand command)
{
    this.logger.LogInformation("Executing CreatePlayerCommand for {PlayerId}", command.AggregateRootId);

    try
    {
        // Validation logic
        this.logger.LogDebug("Validation passed for {PlayerId}", command.AggregateRootId);

        // Event creation
        var @event = new PlayerCreatedEvent { /* ... */ };
        this.RaiseEvent(@event);

        this.logger.LogInformation("Successfully created PlayerCreatedEvent for {PlayerId}", command.AggregateRootId);
    }
    catch (Exception ex)
    {
        this.logger.LogError(ex, "Failed to execute CreatePlayerCommand for {PlayerId}", command.AggregateRootId);
        throw;
    }
}

Event Store Issues

Symptoms: Events not being persisted or loaded correctly

Diagnostics:

-- Check event storage
SELECT stream_id, type, data, timestamp 
FROM mt_events 
WHERE stream_id = 'player-12345'
ORDER BY version;

-- Check for event processing errors
SELECT * FROM mt_event_progression WHERE last_exception IS NOT NULL;

Projection Failures

Symptoms: Read models not updating after commands

Debugging:

// Add logging to projection builders
public void Apply(PlayerCreatedEvent @event, PlayerContract contract)
{
    this.logger.LogDebug("Applying PlayerCreatedEvent {EventId} to contract {ContractId}", 
        @event.Id, contract.Id);

    contract.Id = @event.AggregateRootId.Value;
    contract.PlayerName = @event.PlayerName;
    // ... other properties

    this.logger.LogDebug("Successfully applied PlayerCreatedEvent to contract {ContractId}", contract.Id);
}

Authorization Issues

Role-Based Access Problems

Symptoms: "Access denied" errors for valid users

Debugging:

// Add authorization logging
[RequiresRoles(RoleDefinition.Member)]
public class MyCommand : DomainCommand<MyId>, IRequiresUserContext
{
    public ClaimsPrincipal? User => UserContext.Current;
}

// In SecurityCommandExecutor
public async Task<IReadOnlyList<IDomainEvent>> ExecuteAsync<TId>(IDomainCommand<TId> command, int expectedVersion)
{
    this.logger.LogDebug("Checking authorization for command {CommandType}", command.GetType().Name);

    var requiredRoles = this.securityMapping.GetRequiredRoles(command.GetType());
    this.logger.LogDebug("Required roles: {Roles}", string.Join(", ", requiredRoles ?? Array.Empty<string>()));

    var user = UserContext.Current;
    var userRoles = user?.FindAll(ClaimTypes.Role).Select(c => c.Value).ToArray() ?? Array.Empty<string>();
    this.logger.LogDebug("User roles: {UserRoles}", string.Join(", ", userRoles));

    // ... authorization logic
}

Security Mapping Issues

Symptoms: Authorization attributes not being detected

Solutions: 1. Verify attribute placement on command/query classes 2. Check assembly scanning in startup 3. Validate role definitions match exactly 4. Ensure ISecurityMapping is registered in DI

Testing Issues

Test Database Problems

Symptoms: Tests failing due to database state

Solutions:

// Use proper test isolation
[SetUp]
public async Task SetUp()
{
    // Create test database session
    this.session = this.store.LightweightSession();

    // Clear any existing data
    await this.session.DeleteWhere<PlayerContract>(x => true);
    await this.session.SaveChangesAsync();
}

[TearDown]
public void TearDown()
{
    this.session?.Dispose();
}

Authorization Test Failures

Symptoms: Authorization tests not working correctly

Solutions:

// Use proper test helpers
[Test]
public async Task MyCommand_WithValidRole_ShouldSucceed()
{
    // Use the authorization test helper
    using (AuthorizationTestHelpers.SetTestUser(RoleDefinition.Member))
    {
        var command = new MyCommand { /* ... */ };
        var events = await this.commandExecutor.ExecuteAsync(command, 0);
        events.Should().HaveCount(1);
    }
}

Performance Issues

Slow Query Performance

Symptoms: Queries taking too long to execute

Diagnostics:

-- Check query execution plans
EXPLAIN ANALYZE SELECT * FROM player_contracts WHERE team_id = 'team-123';

-- Check missing indexes
SELECT schemaname, tablename, attname, n_distinct, correlation 
FROM pg_stats 
WHERE tablename = 'player_contracts';

Solutions: 1. Add appropriate indexes to read model contracts 2. Optimize query filters and ordering 3. Consider pagination for large result sets 4. Use appropriate session types (lightweight vs identity)

Memory Issues

Symptoms: High memory usage or OutOfMemoryException

Solutions:

// Use proper session disposal
public async Task<IEnumerable<PlayerContract>> GetPlayersAsync()
{
    using var session = this.store.LightweightSession();
    return await session.Query<PlayerContract>().ToListAsync();
}

// Avoid loading large aggregates
// Use snapshots for aggregates with many events
public class PlayerAggregateWithSnapshot : PlayerAggregate, ISnapshot
{
    // Implement snapshot functionality
}

Development Tools

Aspire Dashboard

Access: http://localhost:15000

Use for: - Monitoring service health - Viewing application logs - Checking HTTP requests/responses - Database connection monitoring

Database Administration

# Connect to development database
psql -h localhost -U lbs_dev lbs_foundry_dev

# Useful queries
-- Check event streams
SELECT DISTINCT stream_id FROM mt_events LIMIT 10;

-- Check projections
SELECT name, lifecycle, last_seq_id FROM mt_event_progression;

-- Check read models
SELECT count(*) FROM player_contracts;

API Testing

Swagger UI: http://localhost:5000/swagger

Postman Collection:

{
  "info": { "name": "LBS Foundry API" },
  "item": [
    {
      "name": "Query Players",
      "request": {
        "method": "POST",
        "url": "{{baseUrl}}/api/readmodel",
        "body": {
          "mode": "raw",
          "raw": "{\n  \"query\": {\n    \"queryType\": \"PlayerSearch\",\n    \"searchTerm\": \"smith\"\n  },\n  \"dataType\": \"PlayerContract\"\n}"
        }
      }
    }
  ]
}

Monitoring and Observability

Application Logging

Configuration (appsettings.json):

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "LBS": "Debug",
      "Microsoft.AspNetCore": "Warning"
    }
  }
}

Structured Logging:

this.logger.LogInformation("Player created with ID {PlayerId} and name {PlayerName}", 
    playerId, playerName);

this.logger.LogError(exception, "Failed to process command {CommandType} for aggregate {AggregateId}", 
    command.GetType().Name, command.AggregateRootId);

Performance Monitoring

// Add timing to critical operations
public async Task<IReadOnlyList<IDomainEvent>> ExecuteAsync<TId>(IDomainCommand<TId> command, int expectedVersion)
{
    using var activity = this.activitySource.StartActivity("CommandExecution");
    activity?.SetTag("command.type", command.GetType().Name);
    activity?.SetTag("aggregate.id", command.AggregateRootId.ToString());

    var stopwatch = Stopwatch.StartNew();

    try
    {
        var result = await this.innerExecutor.ExecuteAsync(command, expectedVersion);

        activity?.SetTag("events.count", result.Count);
        this.logger.LogInformation("Command {CommandType} executed in {ElapsedMs}ms", 
            command.GetType().Name, stopwatch.ElapsedMilliseconds);

        return result;
    }
    catch (Exception ex)
    {
        activity?.SetStatus(ActivityStatusCode.Error, ex.Message);
        throw;
    }
}

When All Else Fails

Nuclear Options (Development Only)

# Complete reset - use with caution!

# 1. Reset git state
git clean -fdx
git reset --hard HEAD

# 2. Reset database
dropdb lbs_foundry_dev
createdb lbs_foundry_dev

# 3. Clear all caches
dotnet nuget locals all --clear
rm -rf node_modules sdk/typescript/node_modules src/Apps/foundry-web/node_modules

# 4. Fresh setup (Marten applies the schema on host startup — no migration step)
dotnet restore LBS.slnx
dotnet build LBS.slnx
pnpm install
pnpm sdk:refresh
dotnet run --project src/Apps/LBS.Api/LBS.Api.csproj

Getting Help

  1. Check logs in Aspire dashboard first
  2. Search this troubleshooting guide for similar issues
  3. Ask in development channel with:
  4. Error message/symptoms
  5. Steps to reproduce
  6. What you've already tried
  7. Relevant log output
  8. Create an issue for reproducible bugs

Still stuck? The development team is here to help! Don't hesitate to ask questions.