Chapter 4: Production Gotchas - 5 Real-World Bugs
Everything works perfectly in localhost. Then you deploy to production, and real users find problems you never imagined.
This chapter covers five classic production bugs our team encountered in real projects, along with Vibe Coding solutions.
Why Production Bugs Happen
Localhost is a controlled environment. Production is chaos:
- Different browsers, devices, and operating systems
- Browser extensions that modify web pages
- Network latency and intermittent connectivity
- Third-party API rate limits and downtime
- Configuration differences between environments
Understanding what can go wrong helps you build more resilient applications.
Bug 1: Google Translate Crashes React (Hydration Error)
Symptom
Users with Chrome Google Translate extension enabled see a white screen when interacting with the page. The console shows:
NotFoundError: Failed to execute removeChild on Node: The node to be removed is not a child of this node.
Root Cause
Google Translate secretly wraps translated text in tags, modifying the DOM tree. React's Virtual DOM tracker loses synchronization with the actual DOM, causing a hydration crash during re-renders.
Fix: Monkey Patch
Inject a script that intercepts the error before it crashes the app:
// Add to layout.tsx <head>
(function() {
const originalRemoveChild = Node.prototype.removeChild;
Node.prototype.removeChild = function(child) {
if (child.parentNode !== this) {
console.warn("Google Translate DOM conflict intercepted");
return child;
}
return originalRemoveChild.call(this, child);
};
})();
Bug 2: Google Translate Also Translates Your Language Menu
Symptom
Your beautiful language switcher has options like "English" and "繁體中文." When Google Translate activates, even the menu options get translated. Users cannot switch back to the original language.
Fix: The notranslate Attribute
Add these attributes to elements that must never be translated:
<div className="notranslate" translate="no">
<select>
<option value="en">English</option>
<option value="zh-TW">繁體中文</option>
</select>
</div>
Google Translate respects these attributes and skips the protected elements.
Bug 3: React State Resets After Translation
Symptom
The page is in Japanese, but the language dropdown shows "繁體中文." The page translated correctly, but the UI state reset.
Root Cause
Google Translate's DOM manipulation triggers React re-renders, resetting useState to initial values.
Fix: Read Language from Cookie
Google Translate stores the current language in a cookie named "googtrans." Read this cookie on component mount:
useEffect(() => {
const match = document.cookie.match(/googtrans=(.+)/);
if (match) {
const lang = match[1].split("/")[1];
setCurrentLang(lang);
}
}, []);
Bug 4: ECPay Blocks International Credit Cards
Symptom
Overseas customers from the US or Hong Kong see "Transaction Failed" when trying to pay. Your code is correct, the CheckMacValue is valid.
Root Cause
ECPay disables international card transactions by default for new merchants. This is a fraud prevention measure.
Fix: Manual Activation
This cannot be fixed in code. You must:
- Log into the ECPay merchant dashboard
- Contact customer support
- Request activation of "International Credit Card Transactions (including 3D verification)"
For businesses targeting international customers, consider adding Stripe or PayPal as a secondary payment option. These platforms have higher international card success rates.
Bug 5: Accidental Database Table Deletion
Symptom
You drop the vt_purchases table in Supabase dashboard. All users immediately lose access to purchased courses.
Fix: SQL Resurrection Script
If you keep your original SQL schema script ready, you can restore within seconds:
CREATE TABLE public.vt_purchases (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
user_id UUID REFERENCES auth.users NOT NULL,
course_id TEXT NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW()
);
ALTER TABLE public.vt_purchases ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Users can see own purchases"
ON public.vt_purchases FOR SELECT
USING (auth.uid() = user_id);
CREATE POLICY "System can insert purchases"
ON public.vt_purchases FOR INSERT
WITH CHECK (true);
Always keep your schema scripts version-controlled and readily accessible.
General Production Prevention
| Issue | Prevention Strategy | |-------|--------------------| | Missing env vars | Startup validation script | | DB migration conflicts | Timestamp-prefixed migration files | | CORS misconfiguration | Environment-based CORS origins | | API key expiration | Calendar reminders + health checks | | Log explosion | Production log level = warn/error |
The Debugging Mindset
When encountering a production bug:
- Do not panic - most bugs have logical causes
- Reproduce the issue in a controlled environment
- Isolate the root cause (browser extension? network? config?)
- Search for similar issues (Google, Stack Overflow, AI)
- Apply the fix and verify it works
- Add monitoring to detect recurrence
Chapter Summary
Production bugs are inevitable. The key is knowing what can go wrong and having recovery plans ready. Most production issues are not coding errors - they are environment, configuration, or third-party integration problems.
Key takeaways:
- Google Translate can crash React via DOM manipulation
- Use notranslate attributes and monkey patches for defense
- ECPay blocks international cards by default - request activation
- Keep SQL schema scripts ready for emergency recovery
- Validate environment variables on startup
- Add monitoring to detect issues early
What's Next: Sitemap & Search Engine Indexing
The next chapter shows you how to help Google find and index your website content with sitemap.xml and robots.txt.
Additional Gotchas from Real Projects
The CORS Nightmare
Symptom: Frontend can call your API in development, but after deployment, all API calls fail with CORS errors.
Root Cause: You hardcoded "http://localhost:3000" as the allowed origin in your CORS configuration.
Fix: Use environment variables for CORS origins:
const corsOptions = {
origin: process.env.CORS_ORIGIN || "http://localhost:3000",
credentials: true
};
app.use(cors(corsOptions));
The Third-Party API Key Expiration
Symptom: A feature that worked yesterday suddenly stopped working. No code changes were made.
Root Cause: A third-party API key expired. The free trial period ended, or the key was revoked.
Fix:
- Set calendar reminders for key renewal dates
- Implement health checks that monitor API response status
- Add monitoring alerts for API failures
The Log Overflow
Symptom: The server disk is full. The application crashes.
Root Cause: console.log statements left in production code, combined with an infinite loop, generated terabytes of logs.
Fix:
- Use a logging library with configurable log levels
- Set production log level to "warn" or "error"
- Implement log rotation and retention policies
- Monitor disk usage with alerts
Building Resilient Systems
Production reliability comes from anticipating failure:
| Principle | Implementation | |-----------|----------------| | Fail fast | Validate inputs immediately | | Graceful degradation | Show fallback UI when APIs fail | | Redundancy | Multiple instances behind load balancer | | Monitoring | Track error rates, response times, uptime | | Backup | Automated daily backups with point-in-time recovery | | Rollback | Keep previous deployment versions ready |
Chapter Summary (Extended)
The bugs in this chapter are just a sample of what can go wrong. The key lessons are:
- Browser extensions can break your JavaScript app in unexpected ways
- Payment gateways have business rules that override technical correctness
- Always keep database schema scripts version-controlled
- Use environment variables for all environment-specific configuration
- Monitor third-party API health and key expiration dates
- Set appropriate log levels for production environments
By understanding these failure modes, you can build more resilient applications and respond to production issues with confidence.