# 錯誤

> VimineError——API 和 SDK 可能拒絕的一切都使用同一種錯誤型別，並帶有穩定的錯誤碼。

URL: https://developers.vimine.network/zh-hant/sdk/errors/

```js
import { VimineError } from '@vimine/sdk';   // 也可從 /server 匯入
```

所有出錯的情況都以 `VimineError` 的形式出現，它是 `Error` 的子類別。**`code`** 是用於分支判斷的穩定識別碼：它可以是 problem+json 文件（RFC 9457）的 `code`、OAuth 回應的 `error`，或 SDK 自己的錯誤碼之一。

## 屬性

| | 型別 | |
|---|---|---|
| `code` | `string` | 穩定的錯誤碼 |
| `message` | `string` | problem 的 `detail` 或 `title`，或 `error_description` |
| `status` | `number \| null` | HTTP 狀態碼，本機錯誤為 `null` |
| `requestId` | `string \| null` | 回應的 `request_id`：報告問題時請註明 |
| `detail` | `string \| null` | problem 的 `detail` |
| `errors` | `FieldError[]`——`{ field?, code?, message? }` | `validation_failed` 和 `identification_required` 的詳細資訊；`codicefiscale_mismatch` 記錄還帶有 `mismatches`、`hints` 和 `confirmable`（[指南](https://developers.vimine.network/zh-hant/guides/members-without-cf/#不一致的稅號與確認)） |
| `cause` | `unknown` | 底層錯誤（`network`、`framed`） |
| `isAuthError` | `boolean` | 表示“工作階段已失效：請重新登入”時為 `true`（401、`invalid_token`、`token_expired`、`missing_token`、`invalid_grant`、`not_signed_in`） |

## SDK 自己的錯誤碼

| `code` | 何時出現 |
|---|---|
| `invalid_options` | 建構函式缺少 `clientId`、`redirectUri` 或 `clientSecret` |
| `network` | 請求未能到達 API（`cause` 帶有原始錯誤） |
| `not_signed_in` | 進行經過驗證的呼叫時沒有工作階段，或沒有重新整理權杖 |
| `no_flow` | 收到返回，但本瀏覽器沒有發起過登入（儲存為空或已過期） |
| `state_mismatch` | 返回與發起的登入不符 |
| `framed` | 在跨網域框架中呼叫了 `signIn()` |
| `http_<status>` | 錯誤回應沒有可識別的 JSON 本文 |

**API** 錯誤碼（`insufficient_scope`、`not_found`、`validation_failed`、`statuto_required`、`rate_limited` 等）和 **OAuth** 錯誤碼（`invalid_grant`、`access_denied`、`unauthorized_client` 等）見[權限、錯誤與限制](https://developers.vimine.network/zh-hant/guides/scopes-and-errors/)。

## 處理錯誤

```js
import { VimineError } from '@vimine/sdk';

try {
    await vimine.membership.acceptStatuto({ version });
} catch (err) {
    if (!(err instanceof VimineError)) throw err;
    if (err.isAuthError) return vimine.signIn({ returnTo: location.pathname });
    switch (err.code) {
        case 'statuto_outdated':  return alert(`已有更新的版本生效：${err.detail}`);
        case 'insufficient_scope': return vimine.signIn({ scopes: ['statuto:accept'], prompt: 'consent' });
        case 'rate_limited':      return setTimeout(retry, 5000);
        default:                  console.error(err.code, err.requestId);
    }
}
```
