> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lasersell.io/llms.txt
> Use this file to discover all available pages before exploring further.

# 错误处理

> LaserSell API 的 HTTP 状态码、错误信封格式、ExitApiError 类型和重试行为。

## HTTP 状态码

| 状态  | 含义                         | 可重试    |
| --- | -------------------------- | ------ |
| 200 | 成功                         | 不适用    |
| 400 | 错误请求（无效参数、无效代币地址、不支持的代币程序） | 否      |
| 401 | 未授权（缺少或无效的 API 密钥）         | 否      |
| 404 | 不支持的市场或代币地址尚未索引            | 否（见下文） |
| 422 | 无法处理（有效请求但无可用路由）           | 否      |
| 429 | 速率限制                       | 是      |
| 502 | 网关错误（上游 RPC 或 DEX 故障）      | 是      |
| 503 | 服务不可用（路由器未就绪或已暂停）          | 是      |
| 500 | 内部服务器错误                    | 是      |

## 响应信封

### 成功

```json theme={null}
{
  "status": "ok",
  "tx": "base64-encoded unsigned transaction",
  "route": { "market_type": "pumpswap", "pool_id": "..." }
}
```

### 不支持的市场

当代币在任何支持的 DEX 上没有可用路由时返回。`message` 字段提供人类和 AI 可读的说明。

```json theme={null}
{
  "status": "unsupported",
  "reason": "no_route",
  "message": "No supported market found for this mint. Supported DEXs: PumpSwap, Raydium (CPMM, Launchpad), Meteora (DBC, DAMM v2), Pump.fun."
}
```

| 原因                          | 状态  | 说明                                |
| --------------------------- | --- | --------------------------------- |
| `no_route`                  | 404 | 没有支持的 DEX 有此代币的池                  |
| `invalid_mint`              | 400 | 代币地址在链上不存在                        |
| `unsupported_token_program` | 400 | 代币使用 SPL Token 或 Token-2022 以外的程序 |

### 未索引

当代币存在但尚未解析时返回。短暂延迟后重试。

```json theme={null}
{
  "status": "not_indexed",
  "mint": "So11111111111111111111111111111111111111112",
  "reason": "mint not indexed yet; try again shortly"
}
```

### 错误

验证失败、速率限制和服务器错误的通用错误响应。

```json theme={null}
{
  "error": "descriptive error message"
}
```

SDK 解析所有响应变体，并通过 `ExitApiError` 类型呈现。

## `ExitApiError` 类型

每个 SDK 都暴露一个带有 `kind` 判别器的 `ExitApiError`（或等效类型）：

| Kind              | 触发条件                          | 可重试                |
| ----------------- | ----------------------------- | ------------------ |
| `transport`       | 网络故障、DNS 错误、超时                | 是                  |
| `http_status`     | 非 2xx HTTP 响应                 | 状态 >= 500 或 429 时是 |
| `envelope_status` | 服务器返回 `{ "status": "error" }` | 否                  |
| `parse`           | 响应体无法解析为 JSON                 | 否                  |

### 检查可重试性

<CodeGroup>
  ```typescript TypeScript theme={null}
  import { ExitApiError } from "@lasersell/lasersell-sdk";

  try {
    const response = await client.buildSellTx(request);
  } catch (error) {
    if (error instanceof ExitApiError) {
      console.log("Kind:", error.kind);
      console.log("Retryable:", error.isRetryable());
      console.log("HTTP status:", error.status);
      console.log("Body:", error.body);
    }
  }
  ```

  ```python Python theme={null}
  from lasersell_sdk.exit_api import ExitApiError

  try:
      response = await client.build_sell_tx(request)
  except ExitApiError as error:
      print("Kind:", error.kind)
      print("Retryable:", error.is_retryable())
      print("HTTP status:", error.status)
      print("Body:", error.body)
  ```

  ```rust Rust theme={null}
  use lasersell_sdk::exit_api::ExitApiError;

  match client.build_sell_tx(&request).await {
      Ok(response) => { /* use response */ }
      Err(error) => {
          eprintln!("Kind: {:?}", error.kind());
          eprintln!("Retryable: {}", error.is_retryable());
      }
  }
  ```

  ```go Go theme={null}
  import lasersell "github.com/lasersell/lasersell-sdk/go"

  resp, err := client.BuildSellTx(ctx, request)
  if err != nil {
      var apiErr *lasersell.ExitAPIError
      if errors.As(err, &apiErr) {
          fmt.Println("Kind:", apiErr.Kind)
          fmt.Println("Retryable:", apiErr.IsRetryable())
          fmt.Println("HTTP status:", apiErr.Status)
      }
  }
  ```
</CodeGroup>

## 内置重试行为

所有 SDK 包含自动重试，默认值如下：

| 设置     | 默认值    |
| ------ | ------ |
| 最大尝试次数 | 2      |
| 初始退避   | 25 ms  |
| 最大退避   | 25 ms  |
| 抖动     | 25 ms  |
| 连接超时   | 200 ms |
| 尝试超时   | 900 ms |

重试仅在 `isRetryable()` 返回 `true` 时触发（传输故障、5xx 响应和 429 速率限制）。

### 自定义重试策略

<CodeGroup>
  ```typescript TypeScript theme={null}
  const client = ExitApiClient.withOptions("YOUR_API_KEY", {
    attempt_timeout_ms: 2000,
    retry_policy: {
      max_attempts: 3,
      initial_backoff_ms: 50,
      max_backoff_ms: 200,
      jitter_ms: 50,
    },
  });
  ```

  ```python Python theme={null}
  from lasersell_sdk.exit_api import ExitApiClient, ExitApiClientOptions
  from lasersell_sdk.retry import RetryPolicy

  client = ExitApiClient.with_options(
      "YOUR_API_KEY",
      ExitApiClientOptions(
          attempt_timeout_s=2.0,
          retry_policy=RetryPolicy(
              max_attempts=3,
              initial_backoff_ms=50,
              max_backoff_ms=200,
              jitter_ms=50,
          ),
      ),
  )
  ```

  ```rust Rust theme={null}
  use std::time::Duration;
  use lasersell_sdk::exit_api::{ExitApiClient, ExitApiClientOptions};
  use lasersell_sdk::retry::RetryPolicy;
  use secrecy::SecretString;

  let client = ExitApiClient::with_options(
      Some(SecretString::new("YOUR_API_KEY".into())),
      ExitApiClientOptions {
          connect_timeout: Duration::from_millis(200),
          attempt_timeout: Duration::from_millis(2000),
          retry_policy: RetryPolicy {
              max_attempts: 3,
              initial_backoff: Duration::from_millis(50),
              max_backoff: Duration::from_millis(200),
              jitter: Duration::from_millis(50),
          },
      },
  )?;
  ```

  ```go Go theme={null}
  import (
      "time"
      lasersell "github.com/lasersell/lasersell-sdk/go"
  )

  client := lasersell.NewExitAPIClientWithOptions("YOUR_API_KEY", lasersell.ExitAPIClientOptions{
      ConnectTimeout: 200 * time.Millisecond,
      AttemptTimeout: 2000 * time.Millisecond,
      RetryPolicy: lasersell.RetryPolicy{
          MaxAttempts:    3,
          InitialBackoff: 50 * time.Millisecond,
          MaxBackoff:     200 * time.Millisecond,
          Jitter:         50 * time.Millisecond,
      },
  })
  ```
</CodeGroup>

## 最佳实践

* **不要重试** `400`、`401` 或 `422` 错误。这些表示必须在代码中修复的请求或认证问题。
* **不要重试** `404` 且 `"status": "unsupported"` 的响应。该代币没有支持的市场。
* **重试一次** `404` 且 `"status": "not_indexed"` 的响应。代币可能需要一点时间来解析。
* **指数退避** `429` 响应。内置重试自动处理。
* **带退避重试** `502` 和 `503` 错误。这些是暂时的基础设施问题。
* **记录错误详情**，包括 `kind`、`status` 和 `body` 以便调试。
* 如果持续看到 `envelope_status` 错误，验证你的 `mint` 地址和 `user_pubkey` 是否正确。
