Common Backend Issues & Solutions
Troubleshooting guide for common backend-api issues encountered during development
Common Backend Issues & Solutions
Quick reference for common backend issues and their solutions.
Issue #1: Modules Not Persisting (MongoDB Upsert Conflict)
Symptoms
- Frontend sends modules correctly (visible in logs)
- Backend responds with
{ success: true, data: [], total: 0 } - Modules don't appear in MongoDB after save
- After refresh, modules show as "Unknown Module"
Error in Backend Logs
❌ Failed to upsert module [ModuleName]: Updating the path 'createdAt' would create a conflict at 'createdAt'
Root Cause
The upsertMany method was including createdAt in both $set and $setOnInsert operators, which MongoDB doesn't allow.
Solution
Separate the fields - createdAt should ONLY be in $setOnInsert:
// ❌ WRONG
const module = { ...fields, createdAt: now };
await collection.updateOne(
{ _id },
{ $set: module, $setOnInsert: { createdAt: now } },
{ upsert: true }
);
// ✅ CORRECT
const updateDoc = { ...fields, updatedAt: now }; // No createdAt!
await collection.updateOne(
{ _id },
{ $set: updateDoc, $setOnInsert: { createdAt: now } },
{ upsert: true }
);
File Fixed
apis/backend-api/src/app/spaces/space-modules.service.ts - upsertMany() method
Date Fixed
December 1, 2025
Issue #2: Request Body Empty (ValidationPipe Stripping Properties)
Symptoms
- Frontend sends data with properties
- Backend receives empty object
{} - No error messages, just empty body
Root Cause
Global ValidationPipe configured with whitelist: true strips properties that aren't decorated in DTOs. Since we use TypeScript interfaces (not classes with decorators), ALL properties get stripped.
Solution
Configure ValidationPipe to NOT strip properties:
// main.ts
app.useGlobalPipes(
new ValidationPipe({
whitelist: false, // DON'T strip unknown properties
forbidNonWhitelisted: false, // DON'T throw on unknown properties
transform: true,
transformOptions: {
enableImplicitConversion: true
}
})
);
File Fixed
apis/backend-api/src/main.ts
Issue #3: Controller Not Loading
Symptoms
- Endpoint returns 404
- No logs from controller constructor
- Other endpoints in same module work fine
Debugging Steps
Check controller is registered in module:
@Module({ controllers: [SpacesController, SpaceModulesController], // Both listed? })Check for circular dependencies:
// Use forwardRef for circular imports imports: [forwardRef(() => BackendAuthModule)]Add health check endpoint for testing:
@Get('health') healthCheck() { return { status: 'ok', controller: 'SpaceModulesController' }; }Check route conflicts:
- More specific routes should come BEFORE generic ones
/batchshould be before/:id
Issue #4: EADDRINUSE Port Already in Use
Symptoms
Error: listen EADDRINUSE: address already in use 0.0.0.0:3000
Solution
Kill processes using the port:
# Find and kill process
lsof -ti:3000 | xargs kill -9
# Or kill all node processes
pkill -9 node
# Then restart
yarn serve:backend-only
Issue #5: Auth Guard Blocking Requests
Symptoms
- Endpoint returns 401 Unauthorized
- Request has valid JWT token
- Other protected endpoints work
Debugging Steps
Check guard is applied correctly:
@UseGuards(BackendAuthGuard) // Class level OR method level, not bothTest without auth (temporarily):
@Get('test') // No @UseGuards - for testing only! test() { return { ok: true }; }Verify JWT token format:
curl -H "Authorization: Bearer YOUR_TOKEN" http://localhost:3000/api/endpoint
🔍 General Debugging Tips
1. Add Extensive Logging
this.logger.log(`📦 Method called with:`, { param1, param2 });
console.log('RAW BODY:', JSON.stringify(body, null, 2));
2. Test with curl
# GET request
curl http://localhost:3000/api/spaces/SPACE_ID/modules/health
# POST request with body
curl -X POST http://localhost:3000/api/endpoint \
-H "Content-Type: application/json" \
-d '{"key":"value"}'
3. Check Backend Terminal
The terminal shows all NestJS logs including errors that might not be returned to the client.
4. Verify Rebuild
After code changes, ensure the backend has rebuilt:
- Look for
✔ backend-api:build:productionin terminal - Or restart with
yarn serve:backend-only
📋 Quick Checklist for New Endpoints
- Controller registered in module
- Route doesn't conflict with existing routes
- Auth guard applied correctly (if needed)
- DTOs work with ValidationPipe settings
- Upsert operations don't have field conflicts
- Added logging for debugging
- Tested with curl before frontend integration