İçeriğe geç
wedevit

13 Ekim 2026 · 9 dk okuma · yazılım

İlhan Buğra Aslan

Ekranda tek yazan şey “Bir hata oluştu”: hata yönetimi nasıl tasarlanır?


Hata yönetimi tek bir iş değil, üç ayrı karardır: kullanıcı ekranda ne görecek, sistem geriye ne kaydedecek ve uygulama bundan sonra ne yapacak. Çoğu ekip yalnızca birincisini düşünüyor, onu da tek bir genel cümleyle kapatıyor. Tablo tanıdık: kullanıcı ne yapması gerektiğini bilmiyor, destek ekibi gelen ekran görüntüsünden bir şey çıkaramıyor, geliştirici hatayı yeniden üretemediği için "bizde çalışıyor" diyor. Bu üç kararı ayrı ayrı vermek, yeni bir altyapı kurmayı değil, mevcut kodda birkaç sınırı netleştirmeyi gerektiriyor.

Genel hata mesajının faturası destek kuyruğunda kesiliyor

Bir hata ekranının maliyeti, o ekranı gören kullanıcı sayısıyla değil, o ekrandan sonra ne olduğuyla ölçülür. Kullanıcı tekrar deniyor. Sonra bir daha deniyor, bu sefer ödeme iki kez düşüyor. Sonra destek hattını arıyor ve karşısındaki kişinin elinde "bir hata oluştu yazıyormuş" bilgisinden başka bir şey yok.

Bu bir kullanılabilirlik meselesi gibi görünüyor ama tamamı öyle değil. OWASP, 2025'te güncellediği Top 10 listesine A10 Mishandling of Exceptional Conditions başlığını ilk kez ekledi ve altına 24 farklı zayıflık tipini bağladı. Listenin tanımı net: uygulama olağandışı durumu ya engelleyemiyor, ya oluştuğu anda fark edemiyor, ya da sonrasında kötü tepki veriyor. OWASP Top 10 2025'in tamamına bakarken bu maddenin neden yeni olduğunu anlamak kolay: hatanın kendisi değil, hataya verilen tepki açık yaratıyor.

Üç hata türünü ayırmadan tek bir ekran tasarlanamaz

Pratikte karşınıza çıkan her hata üç kümeden birine giriyor ve üçünün de farklı mesajı, farklı durum kodu, farklı log seviyesi ve farklı yeniden deneme politikası olmalı.

  • Kullanıcının düzeltebileceği hata. Eksik alan, geçersiz vergi numarası, limiti aşan dosya. Kullanıcı ne yapacağını öğrenirse sorun biter, loglanması gerekmez bile.
  • Geçici sistem hatası. Zaman aşımı, kilit çakışması, dış servisten gelen 503. Birkaç saniye sonra muhtemelen çalışacak. Burada doğru davranış kullanıcıyı bilgilendirmek değil, çoğu zaman sessizce yeniden denemek.
  • Kalıcı sistem hatası. Beklenmeyen istisna, bozuk veri, eksik yapılandırma. Kullanıcının yapabileceği bir şey yok, birinin müdahale etmesi gerekiyor.

Bu ayrım yoksa kodda tek bir catch bloğu oluşuyor ve o blok her şeye aynı cevabı veriyor. Geçici bir zaman aşımı kalıcı hata gibi kullanıcıya yansıyor, gerçek bir veri bozulması ise "lütfen tekrar deneyin" mesajının arkasında kayboluyor.

Kullanıcıya üç şey söyleyin: ne oldu, ne yapsın, hangi numarayı versin

Jakob Nielsen'in 1994'te yayımladığı on kullanılabilirlik ilkesinden dokuzuncusu doğrudan bu konuda ve otuz yıl sonra hâlâ ihlal ediliyor. Nielsen Norman Group'un hata mesajı rehberi üç şey istiyor: sade dil, sorunun tam olarak ne olduğu ve çözüm önerisi. "Geçersiz giriş" bunların üçünü de karşılamıyor.

Form hataları tarafında bu bir tercih değil, erişilebilirlik ölçütü. WCAG 2.2'de 3.3.1 Error Identification A seviyesinde ve hatalı alanın metinle tanımlanmasını şart koşuyor. 3.3.3 Error Suggestion ise AA seviyesinde ve düzeltmenin nasıl yapılacağının da metinle söylenmesini istiyor, güvenlik gerekçesiyle söylenemediği durumlar hariç. Erişilebilirlik yükümlülükleri tarafında denetime girdiğinizde ilk bakılan yerlerden biri form hataları oluyor.

Üçüncü parça çoğu üründe hiç yok: kullanıcının destek ekibine söyleyebileceği kısa bir referans numarası.

Korelasyon kimliği olmayan hata ekranı destek için kör nokta

Kullanıcıya gösterilen mesajın kısa olması gerekiyor, ama kısa mesajın izinin sürülebilmesi de gerekiyor. İkisini birleştiren şey korelasyon kimliği: istek sisteme girdiği anda üretilen, bütün servislere taşınan, loglara yazılan ve hata ekranında kullanıcıya gösterilen tek bir değer.

Bunun için kendi başlığınızı uydurmanıza gerek yok. W3C'nin Trace Context spesifikasyonu 23 Kasım 2021'de Recommendation oldu ve traceparent başlığıyla istek kimliğini servisler arasında taşımanın standart yolunu tanımlıyor. Çoğu izleme kütüphanesi bunu zaten üretiyor; eksik olan genellikle o kimliği arayüze kadar taşımak ve destek ekranında aranabilir hale getirmek. Destek "referans numarasını okur musunuz" diyebildiği anda ortalama çözüm süresi düşüyor, çünkü arada yapılan tahmin turu ortadan kalkıyor.

API hatası da sözleşmenin parçası

Ekranı düzeltip API'yi olduğu gibi bırakmak yarım iş. Entegre olan taraf, hatayı makine tarafında ayırt edemiyorsa yapabileceği tek şey metni ayrıştırmak, bu da ilk metin değişikliğinde kırılıyor.

Standart hazır: RFC 9457 Problem Details for HTTP APIs, Temmuz 2023'te yayımlandı ve RFC 7807'nin yerini aldı. application/problem+json içerik tipiyle beş alan tanımlıyor: type (problem tipini tanımlayan URI), title (oluşumdan oluşuma değişmeyen kısa başlık), status, detail (bu olaya özel açıklama) ve instance. RFC'nin iki uyarısı özellikle işinize yarıyor. Birincisi, detail alanı "hata ayıklama bilgisi vermek yerine istemcinin sorunu düzeltmesine yardımcı olmaya odaklanmalı". İkincisi, istemciler tanımadıkları ek alanları yok saymak zorunda, yani doğrulama hatalarının listesini kendi uzantı alanınızda taşıyabilir, sözleşmeyi kırmadan genişletebilirsiniz. Hata formatı da API sürümleme kararlarının kapsamına girer, sessizce değiştirmeyin.

Durum kodunu ruh halinize göre seçmeyin

RFC 9110 ayrımı net tutuyor: 4xx sınıfı isteğin hatalı olduğunu ya da karşılanamadığını, 5xx sınıfı sunucunun hata yaptığını ya da isteği yerine getiremediğini söylüyor. 422 Unprocessable Content ise araya giriyor; içerik tipi anlaşılmış, söz dizimi doğru, ama içindeki talimatlar işlenemiyor. İş kuralı doğrulamalarının doğal yeri burası.

Asıl yaygın hata daha baştadır: hata durumunda HTTP 200 dönüp gövdeye {"success": false} yazmak. Bu seçim üç şeyi aynı anda bozar. İzleme sistemi hata oranını göremez, SLO ve hata bütçesi hesabı anlamsızlaşır, ara katmanlar ve önbellekler başarılı sanıp yanıtı saklayabilir, istemci kütüphanelerinin otomatik yeniden deneme mantığı devreye girmez. Durum kodu bir dekorasyon değil, altyapının karar verdiği alan.

Yığın izini kullanıcıya göstermek bir yapılandırma hatası değil, güvenlik açığı

Üretim ortamında ayrıntılı hata sayfası bırakmak, saldırganın ihtiyaç duyduğu keşif bilgisini ücretsiz vermektir. CWE-209 bunu kendi başına bir zayıflık olarak tanımlıyor ve verdiği örnekler tanıdık: tam dosya yolları, veritabanı sorgusunun yapısını ele veren SQL hataları, bağlantı dizgisi içindeki kimlik bilgileri. Önerdiği kural da tek cümle: hata mesajı yalnızca hedef kitlesinin işine yarayan asgari ayrıntıyı içersin, gerisi loga yazılsın.

Pratikte kontrol listesi kısa. Üretimde ayrıntılı hata çıktısı kapalı mı, çerçevenin hata ayıklama kipi kapalı mı, 404 ve 500 sayfaları özelleştirilmiş mi, API yanıtlarında istisna sınıf adı sızıyor mu. Bir de ters yönü unutmayın: hata nesnesini olduğu gibi loglamak, içindeki istek gövdesiyle birlikte parola ve kart verisini de loga taşıyabilir. Log yönetimi tarafında bu veriler bir kez yazıldıktan sonra saklama süresi boyunca orada kalır.

Bir şey ters gittiğinde sistem açık mı kalıyor, kapalı mı?

OWASP'ın A10 başlığı altında saydığı zayıflıklardan biri CWE-636 Not Failing Securely, yani başarısızlık anında güvenli tarafa düşmemek. Soru basit: yetki servisi zaman aşımına uğradığında uygulamanız erişime izin mi veriyor, engelliyor mu? Lisans doğrulaması cevap vermediğinde özellik açık mı kalıyor? Ödeme sağlayıcısı yanıt vermediğinde sipariş ödenmiş sayılıyor mu?

OWASP'ın aynı sayfada verdiği örnek senaryolardan biri tam olarak bu: çok adımlı bir finansal işlemin ortasında bağlantı koptuğunda geri alma mekanizması çalışmazsa durum bozuluyor. Kural, işlemin herhangi bir yerinde kaldıysanız her parçasını geri almak. Ödeme entegrasyonlarında bu kararın karşılığı şudur: "bilinmiyor" diye üçüncü bir durum tutun ve mutabakatla kapatın, zaman aşımını başarı ya da başarısızlık olarak yorumlamayın.

Yeniden deneme, yanlış kurulursa arızayı büyütür

Yeniden deneme yalnızca geçici hatalar için anlamlı. Kalıcı bir 400'ü tekrar denemek sadece yükü artırıyor. Doğru kurulum üç parçadan oluşuyor: üstel geri çekilme, rastgelelik ve üst sınır.

Rastgelelik kısmı genelde atlanıyor ve en pahalı atlama o oluyor. Marc Brooker'ın AWS Architecture blogunda 2015'te yayımladığı Exponential Backoff And Jitter yazısının özeti şu: üstel geri çekilme tek başına yeterli değil, çünkü aynı anda hata alan bütün istemciler aynı anda yeniden deniyor ve zaten zorlanan servisi ikinci kez deviriyor. Araya rastgele gecikme koymak bu dalgayı dağıtıyor. Sunucu tarafında Retry-After başlığıyla ne zaman dönülmesi gerektiğini söylemek de aynı işi yapıyor. Yazma işlemlerinde ayrıca eşsiz bir idempotency anahtarı gerekiyor, yoksa "başarılı ama yanıtı kaybolmuş" bir isteği tekrar denemek ikinci kaydı oluşturuyor. Kullanıcıyı bekletmeyecek işleri arka plan kuyruğuna almak ve yeniden denemeyi orada yönetmek, hem ekranı hem log'u sadeleştiriyor. Dış servis kesintilerine dayanıklılık tarafında devre kesici kalıbı bunun tamamlayıcısı.

Hata yolu da bir kod yoludur ve genelde hiç test edilmemiştir

OWASP'ın A10 için verdiği ilk saldırı senaryosu kaynak tükenmesi: her istisna ardında kilitlenmiş ya da kullanılamaz hale gelmiş bir kaynak bırakıyor, bu birikince sistem duruyor. Sebep neredeyse her zaman aynı, istisna fırlatıldığında bağlantının, dosya tanıtıcısının ya da kilidin kapatıldığı satıra hiç ulaşılmaması.

Bu dallar üretimde ilk kez çalışmasın. Dış servisi zaman aşımına düşüren, 500 döndüren ve bağlantıyı yarıda kesen testler yazın. Yük testi yaparken bağımlılığı kasıtlı yavaşlatıp bağlantı havuzunun davranışına bakın. Kabul testi senaryolarına en az bir hata yolu koyun: ödeme reddedildiğinde kullanıcı ne görüyor, kayıt sırasında e-posta servisi çöktüğünde hesap oluşuyor mu.

Bu haftaya sığan ilk adım

Son otuz günün destek biletlerinden hata ekranı geçen beş tanesini seçin ve her biri için üç soruyu cevaplayın: kullanıcı ne gördü, logda o isteği bulabildiniz mi, bulduysanız ne kadar sürede. Bulamadıklarınız korelasyon kimliği işidir ve genelde bir günlük iştir. Ardından üretimde ayrıntılı hata çıktısının kapalı olduğunu doğrulayın, API'nizin en çok çağrılan üç ucunun hata yanıtını tek bir formata (tercihen application/problem+json) çekin ve dış servis çağrılarınızın hangilerinde geri çekilme ile rastgelelik olduğunu listeleyin.

Bu dört kontrol bir iş gününe sığıyor ve genelde sonraki çeyreğin destek yükünü belirleyen şeyi ortaya çıkarıyor. Mevcut uygulamanızın hata davranışını gözden geçirmemizi isterseniz, elinizdeki destek biletlerinden birkaç örnekle gelin; konuşma soyut bir mimari tartışmasından çok daha hızlı ilerler.


Bu konuda yardıma mı ihtiyacınız var?

iletişime geç →← tüm yazılar