Best Practices for Error Handling in the Backend
Photo By Kostiantyn Li on Unsplash
Errors are bound to happen — whether due to incorrect user input, failed connections, or bugs that slipped through. The main issue isn’t the error itself, but how you handle it.
Note : The code examples in this article use PHP, but you can implement them in other programming languages as needed.
Here are best practices for error handling in the backend that you must apply :
⚠️ Don’t Silently Swallow Exceptions
Avoid writing code like this :
try {
// sesuatu yang bisa gagal
} catch (Exception $e) {
// sengaja dikosongkan 🙃
}
This makes the debugging process much more difficult. It’s better to log the error instead :
catch (Exception $e) {
$logId = uniqid('pay_');
Log::error('Gagal memproses pembayaran', [
'log_id' => $logId,
'user_id' => auth()->id(),
'error' => $e->getMessage()
]);
return response()->json([
'status' => 'error',
'message' => 'Terjadi kesalahan saat memproses pembayaran. Silakan coba lagi nanti.',
'log_id' => $logId,
'error_code' => 'PAYMENT_FAILED'
], 500);
}
Every error has its own specific code. Don’t return 200 OK when the data is not found. For example :
| Situasi | Kode yang Benar |
|---|---|
| Data tidak ditemukan | 404 Not Found |
| Request tidak valid | 400 Bad Request |
| Gagal otorisasi | 401 Unauthorized |
| Error internal server | 500 Internal Server Error |
In addition to the status code, add a specific error_code in the response. This makes it easier for frontend or mobile developers to handle it :
{
"status": "error",
"error_code": "PAYMENT_TIMEOUT",
"message": "Pembayaran gagal karena timeout"
}
This way, the frontend can recognize that the PAYMENT_TIMEOUT error should trigger a specific UI.
Some processes need to keep running even when an error occurs. For example :
- Failed to send an email? Save it to a queue for retrying later.
- Failed to save to Redis? Use the database as a fallback.
- Payment error? Don’t cancel the order immediately mark it as “pending” instead.
Example :
try {
// Coba kirim email
Mail::to($email)->send(new YourMailable());
} catch (Exception $err) {
// Log error dan coba simpan ke antrean retry
Log::error('Gagal kirim email, akan dicoba ulang', ['err' => $err->getMessage()]);
try {
// Simpan ke antrean retry
saveToRetryQueue($emailData);
} catch (Exception $fallback) {
// Jika fallback gagal, log critical error
Log::critical('Gagal menyimpan ke antrean retry', ['err' => $fallback->getMessage()]);
}
}
By applying best practices for error handling in the backend, you’re not just preventing small errors from turning into disasters—you’re also making your system much more stable and developer-friendly.
Note: This article was inspired by a LinkedIn post by Mayank A. discussing best practices in software development. You can read the original version here.