<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Bhandi MANOJ KUMAR</title>
    <description>The latest articles on Forem by Bhandi MANOJ KUMAR (@bhandi_manojkumar_197530).</description>
    <link>https://forem.com/bhandi_manojkumar_197530</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3670161%2Fc7ae715b-6174-42ec-8699-caa8df110541.jpg</url>
      <title>Forem: Bhandi MANOJ KUMAR</title>
      <link>https://forem.com/bhandi_manojkumar_197530</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/bhandi_manojkumar_197530"/>
    <language>en</language>
    <item>
      <title>Your Article Title</title>
      <dc:creator>Bhandi MANOJ KUMAR</dc:creator>
      <pubDate>Fri, 19 Dec 2025 07:53:34 +0000</pubDate>
      <link>https://forem.com/bhandi_manojkumar_197530/your-article-title-1p5d</link>
      <guid>https://forem.com/bhandi_manojkumar_197530/your-article-title-1p5d</guid>
      <description>&lt;p&gt;Stop Exposing Your Database Secrets: A Prisma Exception Filter That Actually Makes Sense&lt;br&gt;
Remember that time your frontend colleague pinged you at 11 PM asking "Bro, what is P2002?"&lt;br&gt;
Turns out, Prisma's default error messages are about as helpful as asking ChatGPT to fix your production bug at 3 AM.&lt;br&gt;
The Problem: Prisma Speaks Database, Users Speak Human&lt;br&gt;
What Prisma returns by default:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
 "statusCode": 500,
 "message": "PrismaClientKnownRequestError: Invalid `prisma.user.create()` invocation in /src/users/users.service.ts:42:38…",
 "error": "Internal Server Error"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What your frontend dev sees: "Bc, database error hai. Fix kar." 🤦‍♂️&lt;br&gt;
What users see: "Sorry, something went wrong. Please try again later." (Translation: We have no idea what broke, but it's definitely your fault for existing.)&lt;br&gt;
What actually happened: Someone tried registering with an email that already exists. That's it. Simple. But Prisma decided to write a 10-line essay about it.&lt;br&gt;
What We Actually Need&lt;br&gt;
Clean. Simple. Actionable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "statusCode": 409,
  "message": "A record with this email already exists",
  "error": "Conflict",
  "timestamp": "2024-12-19T14:30:00.000Z",
  "path": "/auth/register"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Frontend dev: "Perfect, I'll show 'Email already registered. Try logging in.'"&lt;br&gt;
 User: "Oh right, I already have an account."&lt;br&gt;
 You: Finally sleeping before midnight. 🎉&lt;br&gt;
Understanding Prisma Error Codes (The Cheat Sheet)&lt;br&gt;
Prisma error codes are like Aadhaar numbers - looks random, but there's a system:&lt;/p&gt;

&lt;p&gt;Full prisma error reference (Bookmark this)&lt;br&gt;
Building the Filter (The Fun Part)&lt;br&gt;
Create prisma-exception.filter.ts (or whatever you want to name it, I'm not your tech lead):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import {
  ArgumentsHost,
  Catch,
  ExceptionFilter,
  HttpStatus,
  Logger,
} from '@nestjs/common';
import { Prisma } from '@prisma/client';

@Catch(
  Prisma.PrismaClientKnownRequestError,
  Prisma.PrismaClientInitializationError
)
export class PrismaExceptionFilter implements ExceptionFilter {
  private readonly logger = new Logger(PrismaExceptionFilter.name);

  catch(
    exception: Prisma.PrismaClientKnownRequestError | Prisma.PrismaClientInitializationError,
    host: ArgumentsHost
  ): void {
    this.logger.error(exception.message);
    const ctx = host.switchToHttp();
    const response = ctx.getResponse();
    const request = ctx.getRequest();

    // Log for your midnight debugging sessions
    this.logger.error(
      `Prisma Error: ${exception.message}`,
      exception.stack
    );

    let status = HttpStatus.INTERNAL_SERVER_ERROR;
    let message = 'An unexpected database error occurred';

    // Check if it's a known request error (has error code)
    if ('code' in exception) {
      // The magic switch case (copy-paste friendly, you're welcome)
      switch (exception.code) {
        case 'P2002':
          status = HttpStatus.CONFLICT;
          const target = exception.meta?.target as string[];
          message = `A record with this ${target?.[0] || 'field'} already exists`;
          break;

        case 'P2025':
          const isDeleteOperation = 
            request.method === 'DELETE' || 
            exception.message.toLowerCase().includes('delete');

          if (isDeleteOperation) {
            // Idempotent delete - treat as success
            status = HttpStatus.OK;
            message = 'Resource successfully removed';

            this.logger.log(
              `P2025 on DELETE treated as success: ${request.url}`
            );
          } else {
            // Find/update operation - genuine not found
            status = HttpStatus.NOT_FOUND;
            const modelName = (exception.meta as any)?.modelName;
            message = modelName 
              ? `${modelName} not found`
              : 'The requested resource was not found';

            this.logger.warn(
              `P2025 NOT_FOUND: ${request.url} - ${modelName || 'Unknown model'}`
            );
          }
          break;

        case 'P2003':
          status = HttpStatus.BAD_REQUEST;
          message = 'Cannot perform this action due to related records. Please remove related items first';
          break;

        case 'P2011':
          status = HttpStatus.BAD_REQUEST;
          message = 'Required field is missing';
          break;

        case 'P2014':
          status = HttpStatus.CONFLICT;
          message = 'The required relation does not exist or the records are incompatible';
          break;

        case 'P2021':
          status = HttpStatus.INTERNAL_SERVER_ERROR;
          message = 'Database schema error. Please contact support.';
          this.logger.error('CRITICAL: Database table missing. Check migrations!');
          break;

        case 'P1002':
          status = HttpStatus.SERVICE_UNAVAILABLE;
          message = 'Database connection failed. Please try again later';
          break;

        case 'P1003':
          status = HttpStatus.INTERNAL_SERVER_ERROR;
          message = 'Database not found. Tenant may not be provisioned correctly';
          break;

        case 'P1004':
          status = HttpStatus.INTERNAL_SERVER_ERROR;
          message = 'Database access denied. Contact support';
          break;

        case 'P1013':
          status = HttpStatus.INTERNAL_SERVER_ERROR;
          message = 'Invalid database configuration. Contact support';
          break;

        case 'P4024':
          status = HttpStatus.GATEWAY_TIMEOUT;
          message = 'Database request timed out. Please try again';
          break;

        default:
          status = HttpStatus.INTERNAL_SERVER_ERROR;
          message = 'A database error occurred. Please contact support';
      }
    } else {
      // It's an initialization error (connection issues, missing tables, etc.)
      if (exception.message.includes('does not exist')) {
        message = 'Database configuration error. Please contact support.';
        this.logger.error('CRITICAL: Database schema issue detected!');
      } else if (exception.message.includes('timed out')) {
        status = HttpStatus.SERVICE_UNAVAILABLE;
        message = 'Database is temporarily unavailable. Please try again.';
      } else {
        message = 'Service temporarily unavailable. We\'re working on it.';
      }
    }

    response.code(status).send({
      statusCode: status,
      timestamp: new Date().toISOString(),
      path: request.url,
      method: request.method,
      message,
      error: this.getErrorName(status),
    });
  }

  private getErrorName(status: number): string {
    const errorMap: Record&amp;lt;number, string&amp;gt; = {
      [HttpStatus.BAD_REQUEST]: 'Bad Request',
      [HttpStatus.NOT_FOUND]: 'Not Found',
      [HttpStatus.CONFLICT]: 'Conflict',
      [HttpStatus.INTERNAL_SERVER_ERROR]: 'Internal Server Error',
      [HttpStatus.SERVICE_UNAVAILABLE]: 'Service Unavailable',
      [HttpStatus.GATEWAY_TIMEOUT]: 'Gateway Timeout',
    };
    return errorMap[status] || 'Error';
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pro tip: That response.code(status).send() is for Fastify. If you're using Express (why tho?), replace it with response.status(status).json().&lt;br&gt;
Step 2: Register It Globally&lt;br&gt;
In your main.ts:&lt;br&gt;
Done. Every Prisma error in your entire app now goes through this filter.&lt;br&gt;
No more "P2002" showing up in prod and your PM asking "Is this a bug or a feature?" (It's a bug, boss. It's always a bug.)&lt;br&gt;
Real-World Scenarios (The Good Stuff)&lt;br&gt;
Scenario 1: User Registration with Duplicate Email&lt;br&gt;
Without filter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "statusCode": 500,
  "message": "PrismaClientKnownRequestError..."
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Frontend dev: "What do I show the user?"&lt;br&gt;
 You: "Idk, show 'something went wrong'?"&lt;br&gt;
 User: closes tab, never comes back&lt;br&gt;
With filter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "statusCode": 409,
  "message": "A record with this email already exists"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Frontend dev: "Perfect, I'll show 'Email already registered. Try logging in.'"&lt;br&gt;
 User: "Oh right, I already have an account."&lt;br&gt;
Scenario 2: Deleting a Record with Dependencies&lt;br&gt;
Without filter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "statusCode": 500,
  "message": "Foreign key constraint failed..."
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;User clicks delete.&lt;br&gt;
 Error appears.&lt;br&gt;
 User clicks delete again.&lt;br&gt;
 Error appears.&lt;br&gt;
 User rage-quits.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "statusCode": 400,
  "message": "Cannot perform this action due to related records. Please remove related items first."
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;User: "Oh, I need to delete the dependent records first. Makes sense."&lt;br&gt;
Scenario 3: Multi-Tenant SaaS (My Use Case)&lt;br&gt;
I'm building a poultry farm management SaaS (yes, chickens 🐔). Each tenant gets their own database schema.&lt;br&gt;
Problem: Sometimes tenant databases aren't provisioned yet (don't ask why, infra team is "working on it").&lt;br&gt;
Without filter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "statusCode": 500,
  "message": "Database `tenant_abc` does not exist..."
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Client: "Your app is broken."&lt;br&gt;
 Me: "No, your database doesn't exist yet."&lt;br&gt;
 Client: "Same thing."&lt;br&gt;
With filter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "statusCode": 500,
  "message": "Database not found. Tenant may not be provisioned correctly."
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Client opens support ticket.&lt;br&gt;
 Infra team provisions database.&lt;br&gt;
 Problem solved without me getting blamed. 🎯&lt;br&gt;
Scenario 4: The "Table Doesn't Exist" Horror Story&lt;br&gt;
This actually happened to me last week. Deployed to staging, everything worked fine. Deployed to prod, and…&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "statusCode": 500,
  "timestamp": "2025-12-03T16:34:27.567Z",
  "path": "/api/auth/login",
  "method": "POST",
  "message": "\nInvalid `this.prisma.user.findUnique()` invocation in\n/app/apps/api/src/modules/users/users.service.ts:56:29\n\n 53 }\n 54 \n 55 async findByEmail(email: string) {\n→ 56 return this.prisma.user.findUnique(\nThe table `public.users` does not exist in the current database.",
  "error": "PrismaClientKnownRequestError"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Users trying to login: Can't login.&lt;br&gt;
 My PM on Slack: "Is login broken?"&lt;br&gt;
 Me, sweating: "Give me 5 minutes."&lt;br&gt;
 Actual problem: Forgot to run migrations on prod. Classic. 🤦‍♂️&lt;br&gt;
What users saw: That massive error message exposing my file structure (/app/apps/api/src/modules/users/users.service.ts:56:29) and database schema details.&lt;br&gt;
What they SHOULD have seen with our filter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "statusCode": 500,
  "timestamp": "2025-12-03T16:34:27.567Z",
  "path": "/api/auth/login",
  "method": "POST",
  "message": "Service temporarily unavailable. We're working on it.",
  "error": "Internal Server Error"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Clean. Professional. Doesn't expose your entire codebase to the internet.&lt;br&gt;
What I learned:&lt;br&gt;
Always run migrations before deploying (duh)&lt;br&gt;
Test your exception filters with REAL errors (not just unit tests)&lt;br&gt;
Log everything (Future You at 3 AM will be grateful)&lt;br&gt;
Never expose file paths in production (security 101)&lt;br&gt;
Have a rollback plan (for when you inevitably forget migrations again)&lt;/p&gt;

&lt;p&gt;Scenario 5: The "Ghost Delete" Problem&lt;br&gt;
Here's a fun one that bit me while building an article CMS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "statusCode": 500,
  "message": "Invalid `prisma.articleSectionContent.delete()` invocation...\n\nAn operation failed because it depends on one or more records that were required but not found. Record to delete does not exist.",
  "error": "PrismaClientKnownRequestError",
  "code": "P2025"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What happened:&lt;br&gt;
User edited an article section&lt;br&gt;
Frontend sent delete request for content that was already removed&lt;br&gt;
Prisma: "Bro, I can't delete what doesn't exist"&lt;br&gt;
API: throws 500 error&lt;br&gt;
User: "Your app is broken"&lt;/p&gt;

&lt;p&gt;The problem: This is actually NOT an error from the user's perspective. They wanted it deleted. It's deleted (by someone/something else, but still deleted). Mission accomplished, right?&lt;br&gt;
But Prisma treats this as a failure. And if you're not handling P2025 properly, your users see a scary 500 error for a successful operation.&lt;br&gt;
The Right Way to Handle P2025&lt;br&gt;
The philosophy: Is "record not found" an error? Depends on context.&lt;br&gt;
Scenario A - User searching for data:&lt;br&gt;
GET /articles/123&lt;br&gt;
Response: 404 Not Found ❌&lt;br&gt;
Message: "Article not found"&lt;br&gt;
This IS an error. User expected to find something, didn't.&lt;br&gt;
Scenario B- User deleting data:&lt;br&gt;
DELETE /articles/123&lt;br&gt;
Response: 200 OK ✅&lt;br&gt;
Message: "Article deleted"&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;This is NOT an error. User wanted it gone, it's gone. Success!

**Your exception filter should be smart enough to know the difference.** That's why our filter checks the HTTP method and treats DELETE operations as successful even when P2025 occurs.

---

### Why "Ghost Deletes" Happen

**Common scenarios:**

1. **Race conditions:**
   - User clicks delete twice (impatient clicking)
   - Two requests hit server simultaneously
   - First one deletes, second one fails

2. **Stale frontend state:**
   - User has old data cached
   - Tries to delete something that was deleted 5 minutes ago
   - Backend: "What are you even talking about?"

3. **Cascade deletes:**
   - You delete a parent record
   - Prisma cascades and deletes children
   - Your code tries to manually delete a child
   - Too late, it's already gone

4. **Multi-user editing:**
   - User A deletes section 3
   - User B (still on old page) tries to delete section 3
   - Boom, P2025

---

### War Story: The Double-Click Disaster

**2 AM. Production is down.**

Users are mass-reporting: "Can't delete images from articles!"

**Me, frantically checking logs:**

P2025: Record to delete does not exist
P2025: Record to delete does not exist
P2025: Record to delete does not exist

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hundreds of them.&lt;br&gt;
What was happening:&lt;br&gt;
Our upload component had a loading state bug&lt;br&gt;
Users clicked "Delete" once&lt;br&gt;
Nothing happened (UI bug, no loading indicator)&lt;br&gt;
Users clicked again&lt;br&gt;
First request completes → deletes image&lt;br&gt;
Second request arrives → P2025 error → 500 to user&lt;br&gt;
Users panic → click delete again → more 500 errors&lt;br&gt;
Snowball effect&lt;/p&gt;

&lt;p&gt;The fix:&lt;br&gt;
Frontend fix: Disable button on click, show loading&lt;br&gt;
Backend fix: Make deletes idempotent (return 200 for already deleted)&lt;/p&gt;

&lt;p&gt;Time to fix: Frontend PR - 2 hours. Backend filter update - 10 minutes.&lt;br&gt;
Lesson: Good error handling isn't just "nice to have." It prevents production meltdowns caused by UI bugs you didn't even know existed.&lt;br&gt;
Testing Your Filter (Don't Deploy Without This)&lt;br&gt;
Test 1: Unique Constraint Violation&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Create a user
await prisma.user.create({
  data: { email: 'test@example.com', name: 'Test User' }
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Try creating duplicate
await prisma.user.create({
  data: { email: 'test@example.com', name: 'Duplicate Guy' }
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected: 409 Conflict with message "A record with this email already exists"&lt;br&gt;
If you get 500 Internal Server Error, your filter isn't registered properly. Check main.ts.&lt;br&gt;
Test 2: Idempotent Delete&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Delete a record
const article = await prisma.article.create({
  data: { title: 'Test Article', content: 'Test' }
});

await prisma.article.delete({
  where: { id: article.id }
});

// Try deleting again (should NOT throw error)
await prisma.article.delete({
  where: { id: article.id }
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected with filter: 200 OK with message "Resource successfully removed"&lt;br&gt;
Without filter: 500 Internal Server Error (bad UX)&lt;br&gt;
Production Tips (Learn From My Mistakes)&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Don't Leak Database Info
❌ "Table 'users' doesn't exist"
 ✅ "Database error occurred. Contact support."
Why? Because hackers love free intel. Don't help them.&lt;/li&gt;
&lt;li&gt;Log Everything (For Future You)
this.logger.error(
&lt;code&gt;Prisma Error [${exception.code}]: ${exception.message}&lt;/code&gt;,
exception.stack
);
At 3 AM, when prod is down, you'll thank Past You for these logs.&lt;/li&gt;
&lt;li&gt;Monitor Error Rates
If you're seeing P2002 errors spike:
Users are trying to create duplicates (UX issue - maybe add "check availability" button)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you're seeing P2025 errors spike:&lt;br&gt;
Users are trying to access deleted records (cache issue - clear your Redis, bro)&lt;/p&gt;

&lt;p&gt;If you're seeing P4024 errors:&lt;br&gt;
Your queries are too slow (time to add indexes or hire a DBA)&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Make Deletes Idempotent
Bad approach:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Throws error if already deleted
await prisma.article.delete({ where: { id } });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Good approach:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Check first, then delete
const article = await prisma.article.findUnique({ where: { id } });
if (article) {
  await prisma.article.delete({ where: { id } });
}
return { success: true };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Best approach:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Use deleteMany (never throws P2025)
await prisma.article.deleteMany({ where: { id } });
// Returns { count: 0 } if already deleted, { count: 1 } if deleted
return { success: true };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why deleteMany is magic:&lt;br&gt;
Never throws P2025 (just returns count: 0)&lt;br&gt;
Idempotent by design&lt;br&gt;
Less code in your exception filter&lt;/p&gt;

&lt;p&gt;Tradeoff: Can't use relation deletes easily with deleteMany, so pick based on your needs.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Set Up Alerts for Critical Errors
When database tables are missing or connections fail in prod, you want to know IMMEDIATELY:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;case 'P2021':
case 'P1003':
  status = HttpStatus.INTERNAL_SERVER_ERROR;
  message = 'Database schema error. Please contact support.';

  // Alert ops team (Slack, Discord, PagerDuty, whatever)
  await this.sendCriticalAlert({
    error: 'Database schema issue',
    code: exception.code,
    path: request.url,
    message: exception.message
  });
  break;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Trust me, you want this. Finding out about prod issues from your users is embarrassing. Finding out from your monitoring system is professional.&lt;br&gt;
Hall of Shame: Common Deployment Mistakes&lt;br&gt;
Things we've all done:&lt;br&gt;
Pushed to prod without running migrations&lt;br&gt;
Tested on localhost (worked fine), broke in prod (database was different)&lt;br&gt;
Forgot to add new environment variables&lt;br&gt;
Deployed at 5 PM on Friday (rookie mistake)&lt;br&gt;
Hardcoded database credentials (security team wants to talk)&lt;/p&gt;

&lt;p&gt;The fix for all of these: A proper CI/CD pipeline. But until your company approves that budget request, this exception filter will save your ass.&lt;br&gt;
Wrapping Up&lt;br&gt;
What you just built: User-friendly error messages&lt;br&gt;
 Proper HTTP status codes&lt;br&gt;
 No more exposed database internals&lt;br&gt;
 Context-aware error handling (DELETE vs GET)&lt;br&gt;
 Idempotent operations&lt;br&gt;
 Happy frontend developers&lt;br&gt;
 Happy users&lt;br&gt;
 Happy you (no more 11 PM debug calls)&lt;br&gt;
Real talk: This filter won't prevent deployment mistakes (looking at you, P2021). But it WILL prevent those mistakes from exposing your entire codebase to users and hackers.&lt;br&gt;
Defense in depth, baby.&lt;br&gt;
Error happens → Filter catches it → User sees clean message → You fix it → Everyone moves on.&lt;br&gt;
Without filter? Error happens → User sees your file structure → They screenshot it → It ends up on Twitter → Your security team has a breakdown → You're in the incident report → Not a good day.&lt;br&gt;
I know which timeline I prefer.&lt;/p&gt;

&lt;p&gt;About Me&lt;br&gt;
I'm Manoj, a full-stack developer building scalable multi-tenant SaaS applications with NestJS, Prisma, Next.js, and way too much chai ☕.&lt;br&gt;
Currently working on a poultry farm management system that handles real-time data for multiple farms. Yes, seriously. And yes, it's actually interesting when you get past the "wait, chickens?" reaction.&lt;br&gt;
I love architecture, optimization, and the real-world problems we pretend don't exist until 3 AM on a Saturday when production is on fire.&lt;br&gt;
If this helped, drop a ❤️ below. If you have questions or your own 3 AM war stories, drop them in the comments - I reply to everyone (usually with more chai in hand).&lt;br&gt;
Connect: linkedin | github&lt;br&gt;
Related Readings&lt;br&gt;
NestJs Exception Filters (Official Docs)&lt;br&gt;
Never Expose Stack Traces in Prod&lt;/p&gt;

</description>
      <category>security</category>
      <category>database</category>
      <category>backend</category>
      <category>architecture</category>
    </item>
  </channel>
</rss>
