# 错误码

Source: https://docs.simail.ai/zh/errors/

> 错误格式(RFC 9457 problem+json)与 simail 的全部错误码,附 HTTP 状态、能否重试和处理办法。

所有错误都是 `application/problem+json`([RFC 9457](https://www.rfc-editor.org/rfc/rfc9457)),另带几个方便 agent 直接处理的字段:

```json
{
  "type": "https://docs.simail.ai/errors#rate_limited",
  "title": "RateLimitedError",
  "status": 429,
  "detail": "Too many requests.",
  "instance": "/v0/inboxes",
  "name": "RateLimitedError",
  "code": "rate_limited",
  "message": "Too many requests.",
  "fix": "Wait for Retry-After seconds, then retry.",
  "docs": "https://docs.simail.ai/errors#rate_limited",
  "retryable": true,
  "request_id": "req_…"
}
```

| 字段 | 含义 |
|---|---|
| `code` | 稳定的机器可读错误码(见下文);按它分支,不要按 `message` |
| `retryable` | 只有稍后重发同一个请求可能成功时才是 `true` |
| `fix` | 给调用方的一行处理提示(英文) |
| `request_id` | 也在响应头 `x-request-id` 里;联系支持时请附上 |
| `human_message` | 出现时,是写给 agent 背后那个人的话;原样转达 |

每个 `429` 和可重试的 `503` 都带 `Retry-After`。错误正文里从不包含邮件内容、验证码或密钥。

## 给 agent 的规则

1. 按 `code` 分支,不要按 `message`。
2. 只在 `retryable` 为 `true` 时重试:等够 `Retry-After`,再用同一个 `Idempotency-Key` 发**同一个**请求。
3. 错误带 `human_message` 时,原样转给你的主人,然后停下。
4. `signup_closed`、`claim_required`、`human_required`、`thread_locked` 和 `account_suspended` 需要人来决定。不要换 key、邮箱、地址或身份去绕过。
5. 报告问题时附上 `request_id`。

## 错误码

| 错误码 | HTTP | 可重试 |
|---|---|---|
| [`validation_error`](#validation_error) | 400 | 否 |
| [`invalid_request`](#invalid_request) | 400 | 否 |
| [`unauthorized`](#unauthorized) | 401 | 否 |
| [`step_up_required`](#step_up_required) | 401 | 否 |
| [`missing_permission`](#missing_permission) | 403 | 否 |
| [`human_required`](#human_required) | 403 | 否 |
| [`origin_mismatch`](#origin_mismatch) | 403 | 否 |
| [`signup_closed`](#signup_closed) | 403 | 否 |
| [`account_inactive`](#account_inactive) | 403 | 否 |
| [`account_suspended`](#account_suspended) | 403 | 否 |
| [`claim_required`](#claim_required) | 403 | 否 |
| [`invite_invalid`](#invite_invalid) | 403 | 否 |
| [`not_found`](#not_found) | 404 | 否 |
| [`method_not_allowed`](#method_not_allowed) | 405 | 否 |
| [`conflict`](#conflict) | 409 | 否 |
| [`idempotency_conflict`](#idempotency_conflict) | 409 | 否 |
| [`duplicate_send`](#duplicate_send) | 409 | 否 |
| [`address_unavailable`](#address_unavailable) | 409 | 否 |
| [`gone`](#gone) | 410 | 否 |
| [`payload_too_large`](#payload_too_large) | 413 | 否 |
| [`message_too_large`](#message_too_large) | 413 | 否 |
| [`unsupported_media_type`](#unsupported_media_type) | 415 | 否 |
| [`send_blocked`](#send_blocked) | 422 | 否 |
| [`invalid_header`](#invalid_header) | 422 | 否 |
| [`webhook_target_forbidden`](#webhook_target_forbidden) | 422 | 否 |
| [`thread_locked`](#thread_locked) | 423 | 否 |
| [`rate_limited`](#rate_limited) | 429 | 是 |
| [`daily_limit_exceeded`](#daily_limit_exceeded) | 429 | 是 |
| [`internal_error`](#internal_error) | 500 | 是 |
| [`not_implemented`](#not_implemented) | 501 | 否 |
| [`sending_paused`](#sending_paused) | 503 | 是 |
| [`upstream_unavailable`](#upstream_unavailable) | 503 | 是 |

### validation_error

HTTP 400 · 可重试:否 · `ValidationError`

某个字段缺失、类型不对或超出范围。正文带 `errors: [{ path, message }]`。发信没带 `Idempotency-Key`、`POST /v0/waitlist` 里出现 `human_email` 或任何未知字段时,也返回这个错误。

处理:改正 `errors` 里列出的字段后重试。

### invalid_request

HTTP 400 · 可重试:否 · `InvalidRequestError`

请求的格式有问题,但不是某一个字段的问题(比如无法解析的 `page_token`,或把分页令牌、事件游标用在了别的 key 作用域或查询上)。

处理:对照 API 参考检查请求格式。

### unauthorized

HTTP 401 · 可重试:否 · `UnauthorizedError`

API key 缺失、格式错误、已过期或已吊销。不带 key 调 `/mcp` 也会返回它,附一条指向 `/v0/beta` 的 `human_message`。

处理:以 `Authorization: Bearer <key>` 发送有效的 API key。

### step_up_required

HTTP 401 · 可重试:否 · `StepUpRequiredError`

仅控制台:这个操作需要 passkey 验证,或最近 5 分钟内的邮件验证码。

处理:用 passkey 或新的邮件验证码再次验证后重试。

### missing_permission

HTTP 403 · 可重试:否 · `ForbiddenError`

对象在你 key 的作用域内,但 key 缺少相应权限。可能带 `reason`,例如 `inbox_limit`。

处理:换一个有所需权限和作用域的 key。

### human_required

HTTP 403 · 可重试:否 · `HumanRequiredError`

只有人能在控制台里做的事:建 API key 或 webhook、放宽名单、放行被扣留的信、审批发信。

处理:请人到控制台 app.simail.ai 操作。

### origin_mismatch

HTTP 403 · 可重试:否 · `ForbiddenError`

仅控制台:会改变状态的请求不是从 `https://app.simail.ai` 发出的。

处理:控制台 API 只能从控制台页面调用。

### signup_closed

HTTP 403 · 可重试:否 · `SignupClosedError`

内测期间没有有效的定向码就注册。带 `waitlist_url` 和 `human_message`(`en`、`zh`)。不要重试,也不要换用户名或邮箱;把 `human_message` 转给你的主人。见[内测门与等候名单](/zh/beta/)。

处理:不要重试。把 human_message 转给你的主人;在 waitlist_url 加入等候名单。

### account_inactive

HTTP 403 · 可重试:否 · `AccountInactiveError`

仅控制台:账户还在等候名单上、已获邀但未激活,或未通过。

处理:账户还没有激活,请查看状态页。

### account_suspended

HTTP 403 · 可重试:否 · `AccountSuspendedError`

这个组织的发信已暂停(例如退信或投诉激增之后)。收信和阅读照常。控制台会显示原因。

处理:组织的发信已暂停,原因见控制台。

### claim_required

HTTP 403 · 可重试:否 · `ClaimRequiredError`

agent 注册拿到的受限 key 在人认领之前被使用。认领前只有 `GET /v0/auth/me` 和 `GET /v0/beta` 可用。

处理:请你的主人在控制台认领这个邮箱;在那之前只能调用 /v0/auth/me 和 /v0/beta。

### invite_invalid

HTTP 403 · 可重试:否 · `InviteInvalidError`

邀请码不对、已用过、已过期、已吊销,或绑定的是另一个邮箱。连续失败会锁定兑换一小时。

处理:检查邀请码。邀请码只能用一次、会过期,并且只绑定一个邮箱。

### not_found

HTTP 404 · 可重试:否 · `NotFoundError`

对象不存在,**或不在你 key 的作用域内**。simail 从不透露别的组织的对象是否存在。

处理:检查资源 ID,并确认它在你 key 的作用域内。

### method_not_allowed

HTTP 405 · 可重试:否 · `MethodNotAllowedError`

路径存在,但不支持这个 HTTP 方法。

处理:换用支持的 HTTP 方法。

### conflict

HTTP 409 · 可重试:否 · `ConflictError`

对象的状态已经变了。取消发信时,`reason` 为 `already_sending` 或 `already_final`。

处理:重新读取资源,按当前状态再试。

### idempotency_conflict

HTTP 409 · 可重试:否 · `IdempotencyConflictError`

这个 `Idempotency-Key` 已经配过另一份请求正文。

处理:同一个 Idempotency-Key 只能配完全相同的请求正文。

### duplicate_send

HTTP 409 · 可重试:否 · `DuplicateSendError`

去重时间窗内已经发过一封完全相同的信(发件人、收件人、主题和正文都相同)。不要再发。

处理:最近已经发过一封相同的信,不要重发。

### address_unavailable

HTTP 409 · 可重试:否 · `AddressUnavailableError`

用户名已被占用、是保留名、与保留名过于相似,或已退役。地址永远不会转给别的组织。

处理:换一个用户名;这个地址已保留或已退役。

### gone

HTTP 410 · 可重试:否 · `GoneError`

资源已过期或已删除,例如超过 30 天的事件游标。

处理:资源已过期或已删除。

### payload_too_large

HTTP 413 · 可重试:否 · `PayloadTooLargeError`

请求正文超过 1 MiB(带内联附件的发信为 5 MiB)。

处理:减小邮件或附件的大小。

### message_too_large

HTTP 413 · 可重试:否 · `MessageTooLargeError`

外发邮件编码后会超过 5 MiB,或附件超过 32 个。带 `limit_bytes` 和 `estimated_bytes`。

处理:外发邮件连附件约 5 MiB(最多 32 个附件)。删掉或压缩附件。

### unsupported_media_type

HTTP 415 · 可重试:否 · `UnsupportedMediaTypeError`

正文不是 `application/json`。

处理:发送 application/json。

### send_blocked

HTTP 422 · 可重试:否 · `SendBlockedError`

发信前检查拒绝了这封信。`reasons` 列出原因(见[起草与发信](/zh/sending/));`flags` 可能列出风险标记。

处理:发信前检查拒绝了这封信,原因见 `reasons`。

### invalid_header

HTTP 422 · 可重试:否 · `InvalidHeaderError`

某个信头字段(主题、显示名、地址)含有 CR、LF、NUL 或其他控制字符。

处理:去掉信头字段里的 CR、LF、NUL 和不可打印字符。

### webhook_target_forbidden

HTTP 422 · 可重试:否 · `WebhookTargetForbiddenError`

webhook URL 不是 443 端口上的公网 `https://` 主机,或指向 simail 自己的域名。

处理:使用 simail 域名之外的公网 https URL。

### thread_locked

HTTP 423 · 可重试:否 · `ThreadLockedError`

有人接管了这个线程。等 `thread.unlocked`。

处理:有人接管了这个线程;等它解锁。

### rate_limited

HTTP 429 · 可重试:是 · `RateLimitedError`

请求太多。等 `Retry-After` 秒。

处理:等够 Retry-After 秒后重试。

### daily_limit_exceeded

HTTP 429 · 可重试:是 · `DailyLimitExceededError`

某项每日配额已用完。过了 `Retry-After` 再试。

处理:已达到每日发信上限;过了 Retry-After 再试。

### internal_error

HTTP 500 · 可重试:是 · `InternalServerError`

我们这边出了问题。退避后重试;一直失败就报告 `request_id`。

处理:退避后重试;一直失败请报告 request_id。

### not_implemented

HTTP 501 · 可重试:否 · `NotImplementedError`

不提供这个操作。`reason` 为 `not_planned`(例如自定义域名、IMAP/SMTP)或 `phase_2`(日历、文件、关联账户)。

处理:simail 目前不提供这个操作。

### sending_paused

HTTP 503 · 可重试:是 · `SendingPausedError`

全平台暂停发信。已接受的信会等待,恢复后再发出。

处理:平台暂停发信中;稍后重试。

### upstream_unavailable

HTTP 503 · 可重试:是 · `UpstreamUnavailableError`

某个依赖暂时不可用。退避后重试。

处理:退避后重试。
