> For the complete documentation index, see [llms.txt](https://docs.watzap.id/help/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.watzap.id/help/integrations/watzap-sdk/menangani-error.md).

# Menangani Error

Cara membaca error dari WatZap SDK, solusi untuk error yang sering muncul, dan cara menghindari pesan terkirim dobel.

Semua error dari WatZap SDK adalah turunan `WatZapError`. Satu blok `try/catch` sudah cukup untuk menangani semuanya.

```js
import { WatZap, WatZapError, ValidationError, RateLimitError } from '@watzapid/sdk'

const wz = new WatZap()
const noHp = '081234567890'

try {
  await wz.whatsapp.messages.sendText({ to: noHp, text: 'Halo' })
} catch (err) {
  if (!(err instanceof WatZapError)) throw err // error dari kode Kamu sendiri

  if (err instanceof ValidationError) {
    // Data yang dikirim salah atau kurang. Perbaiki dulu, jangan dikirim ulang apa adanya.
  } else if (err instanceof RateLimitError) {
    // Terlalu banyak request. Tunggu err.retryAfterSeconds detik, lalu coba lagi.
  } else if (err.mayHaveBeenProcessed) {
    // Pesan MUNGKIN sudah terkirim (misalnya koneksi putus saat menunggu jawaban).
    // Jangan langsung kirim ulang: catat dulu, lalu cek riwayat pesannya.
  }

  console.error(err.name, err.code, err.message)
}
```

Fungsi yang memanggil server selalu melaporkan masalah lewat error di `await`, termasuk input yang ditolak SDK sebelum dikirim. Ada beberapa pengecualian yang langsung dilempar saat baris itu dijalankan:

* `new WatZap()` tanpa API Key melempar `WatZapError` dengan pesan `Missing API key`.
* `wz.unofficial.device('')` tanpa Number Key melempar `ValidationError` dengan pesan `numberKey is required.` Hal yang sama berlaku untuk `wz.whatsapp.webhook('')` tanpa WABA ID.

## Informasi di setiap error

| Properti               | Isi                                                                                                                                 |
| ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `name`                 | Jenis error, misalnya `RateLimitError`                                                                                              |
| `message`              | Pesan error dari server, atau dari SDK                                                                                              |
| `code`                 | Kode error WatZap, misalnya `'1002'`. Batas kirim Unofficial berisi `'rate_limited'`. Kosong bila input ditolak SDK sebelum dikirim |
| `httpStatus`           | Status HTTP dari server. Kosong bila request belum terkirim atau server tidak menjawab                                              |
| `endpoint`             | Endpoint yang dipanggil, misalnya `'/waba_send_message'`                                                                            |
| `response`             | Isi jawaban server apa adanya                                                                                                       |
| `mayHaveBeenProcessed` | `true` bila request **mungkin sudah diproses** walaupun berakhir error                                                              |
| `retryAfterSeconds`    | Khusus `RateLimitError`: jumlah detik yang perlu ditunggu                                                                           |

{% hint style="info" %}
Jangan menebak jenis error dari `httpStatus`. Sebagian endpoint WatZap menjawab error dengan status HTTP 200. SDK menentukan jenis error dari kode WatZap, jadi pakai `instanceof` seperti contoh di atas.
{% endhint %}

## Jenis error dan solusinya

| Jenis error             | Artinya                                                                                            | Yang perlu dilakukan                                     | Diulang otomatis oleh SDK?                                    |
| ----------------------- | -------------------------------------------------------------------------------------------------- | -------------------------------------------------------- | ------------------------------------------------------------- |
| `ValidationError`       | Ada data yang kurang atau salah                                                                    | Perbaiki datanya, lalu kirim lagi                        | Tidak                                                         |
| `AuthenticationError`   | API Key salah                                                                                      | Cek API Key di member area                               | Tidak                                                         |
| `PermissionDeniedError` | Paket habis atau belum mendukung fitur ini, nomor belum terhubung, atau Number Key milik akun lain | Cek paket dan koneksi nomor di dashboard                 | Tidak                                                         |
| `NotFoundError`         | Data tidak ditemukan, misalnya template, list, pesan, atau Number Key salah                        | Cek nama atau ID yang dipakai                            | Tidak                                                         |
| `ConflictError`         | Data dengan identitas yang sama sudah ada, misalnya subscriber dengan nomor yang sama              | Gunakan data atau ID lain                                | Tidak                                                         |
| `UnprocessableError`    | Request sah tapi tidak bisa diproses, misalnya batas kontak paket sudah tercapai                   | Baca isi `message`                                       | Tidak                                                         |
| `RateLimitError`        | Terlalu banyak request dalam waktu singkat                                                         | Tunggu sesuai `retryAfterSeconds`                        | Ya, bila waktu tunggunya 60 detik atau kurang                 |
| `ProviderError`         | Meta (WABA) atau gateway WhatsApp (Unofficial) menolak pesan                                       | Baca isi `message`                                       | Tidak                                                         |
| `InternalServerError`   | Gangguan di server                                                                                 | Coba lagi beberapa saat kemudian                         | Ya, selama aman                                               |
| `APIConnectionError`    | Server tidak menjawab (internet putus atau server tidak terjangkau)                                | Cek koneksi, dan perhatikan `mayHaveBeenProcessed`       | Ya, selama aman                                               |
| `APITimeoutError`       | Server tidak menjawab dalam batas `timeout`                                                        | Perhatikan `mayHaveBeenProcessed` sebelum mengirim ulang | Ya, kecuali kirim pesan dan aksi lain yang tidak aman diulang |
| `APIUserAbortError`     | Request dibatalkan oleh kode Kamu sendiri lewat `signal`                                           | Tidak perlu tindakan                                     | Tidak                                                         |

Secara bawaan, SDK mencoba ulang maksimal **2 kali** dengan jeda yang makin panjang. Atur jumlahnya lewat opsi `maxRetries`, atau isi `0` untuk mematikannya.

## Pesan mungkin sudah terkirim (`mayHaveBeenProcessed`)

Kalau koneksi putus setelah request sampai ke server, pesan bisa saja sudah terkirim ke pelanggan walaupun kode Kamu menerima error. Karena itu:

* Untuk kirim pesan WhatsApp, SDK **hanya mengulang bila request pasti belum sampai ke server** (misalnya koneksi ditolak, atau ditolak karena batas per menit). Retry dari SDK tidak akan membuat pesan dobel.
* Jika error punya `mayHaveBeenProcessed: true`, **jangan langsung kirim ulang**.
* **WABA**: cek dulu riwayat pesan ke nomor tersebut, seperti contoh di bawah.
* **Unofficial**: tidak ada riwayat kirim yang bisa dicek lewat SDK. Cek manual di WhatsApp nomor pengirim sebelum mengirim ulang.

```js
import { WatZap } from '@watzapid/sdk'

const wz = new WatZap()
const noHp = '081234567890'

const riwayat = await wz.whatsapp.messages.list({ phone: noHp, perPage: 5 })
console.log(riwayat.items.map((pesan) => `${pesan.createdAt}  ${pesan.status}  ${pesan.id}`))
```

Filter `phone` mencocokkan nomor persis seperti saat dikirim. Pesan yang dikirim lewat SDK tersimpan dalam format `+62…`, dan SDK merapikan `noHp` ke format yang sama.

{% hint style="danger" %}
Jangan bungkus fungsi kirim pesan dengan loop retry buatan sendiri. SDK sudah mengulang otomatis saat aman. Retry tambahan berisiko membuat pelanggan menerima pesan yang sama berkali-kali.
{% endhint %}

## Pesan error yang sering muncul

| Pesan error                                                         | Jenis error                                | Penyebab                                                                                    | Solusi                                                                                   |
| ------------------------------------------------------------------- | ------------------------------------------ | ------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| `Missing API key`                                                   | `WatZapError`                              | SDK tidak menemukan API Key                                                                 | Pastikan `WATZAP_API_KEY` terisi dan program dijalankan dengan `--env-file=.env`         |
| `Invalid Secret Key` / `Invalid API Key`                            | `AuthenticationError`                      | API Key salah                                                                               | Salin ulang dari [member area](/help/integrations/mendapatkan-api-key-di-member-area.md) |
| `Need Upgrade Package`                                              | `PermissionDeniedError`                    | Paket belum mendukung kirim pesan lewat API                                                 | Gunakan paket **Plus** atau **Premium**                                                  |
| `Your package is expired` / `Your Package is Expired`               | `PermissionDeniedError`                    | Paket sudah habis                                                                           | [Perpanjang paket langganan](/help/subscription/cara-perpanjang-paket-langganan.md)      |
| `Please Connect WhatsApp Business API First`                        | `PermissionDeniedError`                    | Belum ada nomor WABA yang terhubung                                                         | [Hubungkan nomor WABA](/help/waba-official/cara-connect-nomor-waba-official.md)          |
| `License Not Found`                                                 | `NotFoundError`                            | Number Key salah, atau nomornya sudah dihapus atau dipindah                                 | Cek ulang [Number Key](/help/integrations/mendapatkan-number-key-untuk-api.md)           |
| `Pairing Failed, Access Denied`                                     | `PermissionDeniedError`                    | Number Key milik akun lain, atau memakai API Key akun operator                              | Gunakan API Key akun pemilik                                                             |
| `Kami gagal mengirimkan pesan...` / `WhatsApp Instance Not Started` | `ProviderError` atau `InternalServerError` | Nomor Unofficial sedang tidak terhubung                                                     | Klik **Connect** di tab **API**, lalu scan QR Code lagi                                  |
| `Template not found`                                                | `NotFoundError`                            | Nama atau bahasa template tidak cocok dengan yang ada di WatZap                             | Samakan nama template, dan isi `language` bila ada beberapa bahasa                       |
| `Template parameter tidak lengkap. Missing: …`                      | `ValidationError`                          | Ada variabel template yang belum diisi                                                      | Lengkapi `variables` sesuai variabel di template                                         |
| `Limit Exceeded …`                                                  | `RateLimitError`                           | Lebih dari 30 kirim per menit. Untuk WABA, teks dan template dihitung bersama               | Kirim lebih pelan. SDK menunggu sampai menit berikutnya, lalu mencoba lagi               |
| Pesan dari Meta, misalnya `(#132001) …`                             | `ProviderError`                            | Meta menolak pesan, misalnya template belum disetujui atau tidak ada di nomor WABA pengirim | Baca isi pesan, lalu perbaiki template atau datanya                                      |

{% hint style="info" %}
Pesan teks atau media WABA ke pelanggan yang belum chat dalam 24 jam terakhir biasanya **tidak** langsung menghasilkan error. SDK mengembalikan ID pesan, lalu statusnya berubah menjadi `failed` beberapa saat kemudian. Cek dengan `wz.whatsapp.messages.status(id)`, lalu kirim ulang memakai template. Contohnya ada di [Contoh Use Case](/help/integrations/watzap-sdk/contoh-use-case.md).
{% endhint %}

Kendala kirim lewat API secara umum, termasuk di luar SDK, dibahas di [Solusi Kendala Kirim Pesan via API](/help/integrations/solusi-kendala-kirim-pesan-via-api.md).
