Introduction
Error handling is one of the most critical parts of building reliable web applications. In Laravel 12, error handling has been redefined with a cleaner and more centralized approach using the bootstrap/app.php file, replacing the old Handler.php system.
Whether you’re building an API or a web application, proper error handling ensures that your app behaves predictably, keeps users informed, and protects sensitive information. Unfortunately, many developers fall into bad habits like using dd() in production, returning generic error messages, or ignoring logging altogether.
In this guide, we’ll explore Laravel 12 error handling best practices, highlight common bad practices to avoid, and share practical examples of good implementations. By the end, you’ll know how to build more secure, professional, and user-friendly Laravel applications.
Why Do We Use Error Handling
Error handling is not just about fixing bugs — it’s about building resilient applications that handle unexpected scenarios gracefully. Here’s why it’s essential in Laravel 12 development:
- Improves User Experience (UX): Instead of showing raw errors or stack traces, you can display user-friendly messages.
- Increases Security: Prevents sensitive information (like SQL queries or server details) from being exposed to attackers.
- Helps Debugging: With proper logging and reporting, developers can quickly identify and fix issues.
- Ensures API Reliability: APIs can return structured JSON error responses, making them predictable for clients.
- Boosts Maintainability: Centralized error handling keeps your codebase clean and easier to manage.
In short, error handling in Laravel 12 ensures that your application is secure, stable, and user-friendly in both development and production environments.
🚫 Bad Practices in Error Handling
1. Using dd() or dump() in Production
public function store(Request $request)
{
dd($request->all()); // Debugging in live app
}
Exposes sensitive data (emails, passwords, tokens) and halts the application flow.
2. Leaving APP_DEBUG=true in Production
APP_ENV=production
APP_DEBUG=true
Shows stack traces, SQL queries, and server details to end-users.
A huge security risk — hackers can exploit this information.
3. Ignoring Exception Handling
public function getUser($id)
{
return User::findOrFail($id); // Crashes if user doesn’t exist
}
Unhandled exceptions break the app and return generic 500 errors instead of user-friendly messages.
4. Hardcoding Generic Error Messages
if (!$user) {
return response()->json(['error' => 'Something went wrong']);
}
Confuses users, offers no debugging insight, and makes maintenance harder.
5. Logging Everything as info or error
Log::info('Database connection failed');
Using the wrong log levels buries important issues.
infofor minor eventswarningfor suspicious activityerrorfor failurescriticalfor severe system crashes
6. Mixing HTML Errors in APIs
// Returning HTML in an API response
abort(404, 'Page not found');
APIs should return structured JSON, not Blade views or plain text.
Otherwise, clients (mobile apps, third-party systems) cannot parse responses.
7. Not Creating Custom Exceptions
throw new \Exception('Payment failed');
Using generic exceptions everywhere makes debugging difficult.
Instead, create domain-specific exceptions likeInvalidPaymentExceptionorOrderNotFoundException.
8. Swallowing Errors Without Logging
try {
$user = User::findOrFail($id);
} catch (\Exception $e) {
// Fail silently
}
If you don’t log errors, developers have no way to know what went wrong in production.
Error Handling Best Practices
1. Centralize Exception Handling in bootstrap/app.php
Instead of scattering error handling everywhere, keep it centralized.
<?php
use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
return Application::configure(basePath: dirname(__DIR__))
->withRouting(
web: __DIR__.'/../routes/web.php',
commands: __DIR__.'/../routes/console.php',
health: '/up',
)
->withMiddleware(function (Middleware $middleware) {
//
})
->withExceptions(function (Exceptions $exceptions) {
$exceptions->renderable(function (NotFoundHttpException $e) {
return response()->json([
'message' => 'Record not found.'
], 404);
});
})->create();
Keeps all exception handling consistent.
2. Use Meaningful HTTP Status Codes
Always return the correct status code instead of generic 200 responses.
return response()->json([
'success' => false,
'error' => 'Unauthorized'
], 401);
Helps APIs communicate errors properly.
3. Leverage Built-in Validation
Prevent errors early by validating inputs before processing.
$request->validate([
'email' => 'required|email',
'password' => 'required|min:8',
]);
Stops invalid data from reaching business logic.
4. Use Try-Catch for Critical Operations
Wrap risky operations in try-catch to handle gracefully.
try {
$user = User::findOrFail($id);
} catch (ModelNotFoundException $e) {
return response()->json(['error' => 'User not found'], 404);
}
Prevents application crashes.
5. Log Exceptions with Proper Levels
Don’t log everything as info or error — use levels wisely.
Log::warning('User not found', ['id' => $id]);
Log::error('Database failure', ['exception' => $e]);
Makes debugging easier in production.
6. Report Exceptions in bootstrap/app.php
You can customize reporting separately from rendering.
$exceptions->report(function (Throwable $e) {
Log::critical('System crash detected', [
'message' => $e->getMessage(),
]);
});
Ensures important errors are logged before being displayed.
7. Hide Sensitive Information
Never show stack traces or debug data in production.
APP_ENV=production
APP_DEBUG=false
Protects your app from exposing security vulnerabilities.
8. Customize User-Friendly Error Pages
Provide meaningful error views for users.
{{-- resources/views/errors/404.blade.php --}}
<h1>404 - Page Not Found</h1>
<p>Oops! The page you are looking for doesn’t exist.</p>
<a href="{{ url('/') }}">Go Home</a>
Improves UX while keeping security intact.
9. Return JSON Errors for APIs
APIs should always respond with JSON, not HTML.
$exceptions->render(function (ModelNotFoundException $e, $request) {
if ($request->expectsJson()) {
return response()->json(['error' => 'Record not found'], 404);
}
});
Keeps consistency for API consumers.
10. Use Custom Exceptions for Specific Errors
Instead of using generic errors, create domain-specific exceptions.
// app/Exceptions/InvalidPaymentException.php
class InvalidPaymentException extends \Exception {}
// usage
throw new InvalidPaymentException('Payment method not supported');
Handle it in bootstrap/app.php:
$exceptions->render(function (InvalidPaymentException $e) {
return response()->json(['error' => $e->getMessage()], 400);
});
Makes debugging and maintenance much easier.
Conclusion
Error handling in Laravel 12 has evolved to be more streamlined and developer-friendly. By moving exception handling into the bootstrap/app.php file, Laravel makes it easier to centralize and customize error responses.
Following best practices — such as using proper HTTP status codes, leveraging validation, creating custom exceptions, logging errors correctly, and hiding sensitive details — ensures that your application is both secure and professional.
Ignoring error handling may work in development, but in production, it leads to frustrated users, security risks, and harder debugging. On the other hand, proper error handling builds trust, stability, and scalability into your Laravel projects.
👉 By adopting these Laravel 12 error handling best practices, you’ll not only reduce headaches for your development team but also deliver a better experience for your end users.
If you found this helpful, feel free to share or drop a comment. Happy coding with Laravel! 🧱✨
Free resources for this topic
Code snippets and fixes for this topic
Get one practical tip every week
New tutorials, fixes and free cheat sheets from DEV Talk, straight to your inbox. No spam, unsubscribe in one click.
Free download: Laravel interview questions (PDF)
Have a question about this post?
Ask the community: other developers and the author can answer.
Get notified about new articles
One click, no email needed. Turn it off anytime with the bell at the top.
Get new articles on your iPhone
Add DEV Talk to your Home Screen, open it, then tap the bell.
Enjoying the content?
If this article helped you, you can support the author with a coffee. It keeps new posts coming.
Comments 0
No comments yet
Be the first to share your thoughts.