Hata Kodları
HummyTummy API’sindeki tüm hatalar tek bir standart hata zarfı ile döner.
İstemci tarafında metin mesajına göre değil, kararlı errorCode alanına göre
dallanmanız önerilir.
Hata zarfı
Her hata yanıtı aşağıdaki yapıyı izler:
{
"statusCode": 409,
"message": "User with email '[email protected]' already exists",
"error": "RESOURCE_ALREADY_EXISTS",
"errorCode": "RESOURCE_ALREADY_EXISTS",
"timestamp": "2026-06-23T08:14:05.123Z",
"path": "/api/v1/auth/register",
"requestId": "1750665245123-a1b2c3d4e"
}| Alan | Tip | Açıklama |
|---|---|---|
statusCode | number | HTTP durum kodu. |
message | string | string[] | Kullanıcıya gösterilebilir mesaj. Doğrulama hatalarında bir dizi olabilir. |
error | string | İnsan/kategori etiketi (bazen yerelleştirilmiş ya da class-validator’ın "Bad Request" değeri). Buna göre dallanmayın. |
errorCode | string? | Kararlı, makine-okunur kod. İstemci yalnızca buna göre dallanmalıdır. Yalnızca fırlatılan istisna bir kod iliştirdiğinde bulunur. |
timestamp | string | İstek zaman damgası (ISO 8601). |
path | string | İstek yolu. |
requestId | string? | İzleme için istek kimliği — destek talebinde paylaşın. |
actionable | object? | Yapılandırılmış remediation yükü. Bugün yetki reddini taşır: requirement, offer, licenseRequired, reason. |
details | any? | Yalnızca development ortamında bulunur. |
stack | string? | Yalnızca development ortamında bulunur. |
errorCode PII içermez ve bu nedenle her ortamda (production dahil)
döner. details ve stack ise yalnızca development ortamında yer alır.
error alanı yerelleştirilebilir veya çerçevenin ürettiği bir etikete
düşebilir. Davranışsal dallanmayı her zaman errorCode üzerinden yapın;
errorCode yoksa statusCode’a düşün.
errorCode değerleri
Aşağıdaki kodlar ErrorCode enum’ından gelir ve iş mantığı istisnalarıyla
(BusinessException) iliştirilir.
Bazı kapılar (yetki guard’ı, satın alınabilirlik kapısı, stok kapısı) kendi
kodlarını code alanıyla fırlatır; global hata filtresi bunları
errorCode’a standardize eder. Yani istemci tek bir alana bakar. Bu
kodlar aşağıda Yetki ve satın alma başlığında.
Kimlik doğrulama
errorCode | Anlamı |
|---|---|
INVALID_CREDENTIALS | E-posta veya parola hatalı. |
TOKEN_EXPIRED | Token’ın süresi doldu. |
TOKEN_INVALID | Token geçersiz/bozuk. |
UNAUTHORIZED | Kimlik doğrulama gerekli. |
Yetkilendirme
errorCode | Anlamı |
|---|---|
FORBIDDEN | Erişim reddedildi. |
INSUFFICIENT_PERMISSIONS | Rol/izin bu işlem için yetersiz. |
Kaynak
errorCode | Anlamı |
|---|---|
RESOURCE_NOT_FOUND | İstenen kayıt yok. |
RESOURCE_ALREADY_EXISTS | Aynı kayıt zaten var (ör. yinelenen e-posta). |
RESOURCE_CONFLICT | Kaynağın mevcut durumuyla çakışma. |
Doğrulama
errorCode | Anlamı |
|---|---|
VALIDATION_ERROR | Genel girdi doğrulaması başarısız. |
INVALID_INPUT | Girdi değeri geçersiz. |
MISSING_REQUIRED_FIELD | Zorunlu alan eksik. |
İş mantığı
errorCode | Anlamı |
|---|---|
INSUFFICIENT_STOCK | Ürün için yeterli stok yok. details: { productName, available, requested }. |
ORDER_ALREADY_PAID | Sipariş zaten ödenmiş. |
TABLE_OCCUPIED | Masa dolu. |
INVALID_ORDER_STATUS | İşlem siparişin mevcut durumunda yapılamaz. |
QUOTA_EXCEEDED | Kontör bakiyesi yetersiz (HTTP 402). details: { kind, remaining, requested, offerCode } — offerCode, istemcinin doğrudan derin bağ verebileceği kontör paketidir. |
SUBSCRIPTION_REQUIRED | Devre dışı. Plan rayıyla birlikte emekliye ayrıldı; hiçbir kod yolu artık bunu fırlatmıyor. Enum’da yalnızca eski istemciler kırılmasın diye duruyor. |
FEATURE_NOT_AVAILABLE | Devre dışı. Yerine ENTITLEMENT_REQUIRED (HTTP 403) döner — o zarf eksik yetkiyi ve onu açan ürünü fiyatıyla taşır. |
Ödeme
errorCode | Anlamı |
|---|---|
PAYMENT_FAILED | Ödeme başarısız oldu. |
PAYMENT_PROCESSING_ERROR | Ödeme işlenirken hata. |
INVALID_PAYMENT_METHOD | Geçersiz ödeme yöntemi. |
Sistem
errorCode | Anlamı |
|---|---|
INTERNAL_SERVER_ERROR | Beklenmeyen sunucu hatası. |
SERVICE_UNAVAILABLE | Servis geçici olarak kullanılamıyor. |
DATABASE_ERROR | Veritabanı hatası. |
EXTERNAL_SERVICE_ERROR | Dış servis hatası (ör. ödeme sağlayıcı). |
Hız sınırı
errorCode | Anlamı |
|---|---|
TOO_MANY_REQUESTS | Çok fazla istek (HTTP 429). |
Tenant
errorCode | Anlamı |
|---|---|
TENANT_NOT_FOUND | Tenant bulunamadı. |
INVALID_TENANT | Geçersiz tenant. |
Yetki ve satın alma
Bu kodlar ErrorCode enum’ında değildir; ilgili kapılar code alanıyla
fırlatır, global filtre de bunu errorCode’a taşır — istemci yine tek alana
bakar.
errorCode | HTTP | Anlamı |
|---|---|---|
ENTITLEMENT_REQUIRED | 403 | Rota bir yetki istiyor ve tenant’ta yok. actionable içinde requirement, offer, licenseRequired, reason gelir. |
LICENSE_REQUIRED | 409 | Sepetteki ürün lisans ister; ne sahiplikte ne sepette lisans var. |
ADDON_ALREADY_OWNED | 409 | Ürün (ya da lisans) zaten aktif. |
ADDON_ALREADY_GRANTED | 409 | Ürünün verdiği her şey zaten yetki setinde. |
ADDON_REQUIRES_DEPENDENCY | 409 | Bağımlı olduğu ürün ne sahiplikte ne sepette. |
ADDON_LIMIT_REDUNDANT | 409 | Eklediği kapasite zaten sınırsız. |
ADDON_MAX_QUANTITY | 409 | Katalog adet tavanı aşılıyor. |
HARDWARE_OUT_OF_STOCK | 409 | Donanım satırı için yeterli gerçek stok yok. |
CATALOG_INVALID | 400 | Süperadmin katalog yazımı ürün değişmezlerini ihlal ediyor; message tüm sorunları dizi olarak taşır. |
409 kodlarının tamamı tahsilattan önce, POST /v1/checkout/intent
içinde döner: reddedilen satır sepetin tamamını durdurur, CheckoutIntent
satırı yazılmaz ve PayTR hiç çağrılmaz. Ayrıntılar için
Lisans & Ödeme API ve
Yetki Matrisi.
Veritabanı hatalarının HTTP eşlemesi
Prisma’nın bilinen veritabanı hataları (PrismaClientKnownRequestError) global
istisna filtresinde anlamlı HTTP durum kodlarına çevrilir. Bu yanıtlarda
error alanı kategori etiketini taşır; errorCode bu durumlarda bulunmaz
(bunlar BusinessException değildir).
| Prisma kodu | HTTP | error | Anlamı |
|---|---|---|---|
P2002 | 409 Conflict | UniqueConstraintViolation | Tekil kısıt ihlali (yinelenen kayıt). |
P2025 | 404 Not Found | RecordNotFound | Kayıt bulunamadı. |
P2003 | 400 Bad Request | ForeignKeyConstraintViolation | İlişkili kayıt yok veya bağımlılık nedeniyle silinemiyor. |
P2014 | 400 Bad Request | RequiredRelationViolation | Değişiklik zorunlu bir ilişkiyi ihlal ederdi. |
P2016 | 400 Bad Request | InvalidQuery | Geçersiz sorgu parametreleri. |
P2021 | 500 Internal Server Error | DatabaseConfigError | Tablo yok (yapılandırma hatası). |
P2024 | 503 Service Unavailable | DatabaseTimeout | Veritabanı bağlantı zaman aşımı. |
P2034 | 409 Conflict | ConcurrentUpdate | Serileştirilebilir işlem çakışması (Postgres 40001). İşlem commit olmadı, güvenle yeniden denenebilir. |
P2000, P2020 | 400 Bad Request | ValueOutOfRange | Değer izin verilen aralık dışı veya çok uzun. |
| (diğer) | 500 Internal Server Error | DatabaseError | Eşlenmemiş veritabanı hatası. |
P2034 (ConcurrentUpdate, 409) ödeme uzlaştırma, marketplace satın alma
gibi yarış durumu altındaki Serializable işlemlerin beklenen “kaybeden”
sonucudur ve isteğiniz hiç işlenmemiştir. Bu yanıtı alırsanız isteği aynen
yeniden gönderebilirsiniz.
İstemci tarafında işleme
const res = await fetch('/api/v1/display/orders', { method: 'POST', /* … */ });
if (!res.ok) {
const err = await res.json(); // ErrorResponse
switch (err.errorCode) {
case 'ENTITLEMENT_REQUIRED': {
// 403 — err.actionable.offer, eksik yetkiyi açan ürünü BU tenant için
// bugünkü fiyatıyla taşır. reason === 'lapsed' → "Yenile", aksi → "Satın al".
const { offer, reason, licenseRequired } = err.actionable ?? {};
showPurchasePrompt({ offer, reason, licenseRequired });
break;
}
case 'QUOTA_EXCEEDED':
// 402 — kontör bitti. err.details.offerCode ile kontör paketine derin bağ ver.
break;
case 'LICENSE_REQUIRED':
case 'ADDON_ALREADY_OWNED':
case 'ADDON_ALREADY_GRANTED':
case 'ADDON_REQUIRES_DEPENDENCY':
case 'ADDON_LIMIT_REDUNDANT':
case 'ADDON_MAX_QUANTITY':
// 409 — sepet düzeltilmeli; hiçbir tahsilat yapılmadı.
showToast(err.message);
break;
case undefined:
// errorCode yok → statusCode'a göre dallan (ör. 409 ConcurrentUpdate → retry)
break;
default:
showToast(err.message);
}
}