# 错误与限制

> CardSdkError 和每个错误码、各自的成因与应对方法，以及卡片协议的全部限制一览表。

Source: https://docs.neurosquad.ai/zh/card-sdk/api/errors

## `CardSdkError`

每一次拒绝——无论来自应用，还是来自 SDK 在请求离开卡片之前的自检——都是一个 `CardSdkError`：

```ts
import { CardSdkError, isCardSdkError } from '@neurosquad/card-sdk'

async function saveReport(text: string): Promise<void> {
  try {
    await card.fs.writeText('reports/latest.md', text, { createDirs: true })
  } catch (error) {
    if (isCardSdkError(error, 'PERMISSION_DENIED')) {
      card.ui.toast(`This needs the ${error.permission} permission`)
    } else if (isCardSdkError(error, 'RATE_LIMITED')) {
      await new Promise((resolve) => setTimeout(resolve, error.retryAfterMs ?? 1000))
      return saveReport(text)
    } else if (error instanceof CardSdkError) {
      card.log.error(error.code, error.method, error.hostMessage, error.data)
    } else {
      throw error
    }
  }
}
```

| 属性 | 说明 |
| --- | --- |
| `code` | 下列错误码之一。 |
| `message` | `method: host message [CODE] — hint`，可直接写入日志。 |
| `hostMessage` | 仅应用给出的消息（英文，供开发者看——给用户看的请用你自己的文字）。 |
| `method` | 失败的方法（来自调用时）。 |
| `data` | 详情：schema 问题、`{ permission }`、`{ retryAfterMs }`、`{ conflict }`…… |
| `hint` | 一行建议，仅部分错误码有。 |
| `permission` | `PERMISSION_DENIED` 时：缺少的权限。 |
| `retryAfterMs` | `RATE_LIMITED` 时：需要等待多久。 |
| `issues` | `INVALID_PARAMS` / `BAD_REQUEST` 时：`{ path, keyword, message }[]`——参数哪里不符合。 |

`isCardSdkError(error, code?)` 是一个类型守卫，可选地只匹配某个错误码。

## 错误码

| 错误码 | 含义 | 通常的处理 |
| --- | --- | --- |
| `BAD_REQUEST` | 消息格式错误，或参数不是纯 JSON。 | 参数里有 `Date`、`Map` 或类实例——请发送纯数据。 |
| `INVALID_PARAMS` | 参数不符合该方法的 schema。 | 查看 `error.issues` 中的精确路径。端口值不符合 schema、或引用了未设置的 `{{secret:…}}` 时也是这个错误。 |
| `METHOD_NOT_FOUND` | 应用不认识这个方法。 | 应用版本较旧——用 `card.host.supports()` 检查。 |
| `PERMISSION_DENIED` | 卡片包缺少该权限。 | 在清单中声明它；如果是可选权限，用 `card.permissions.request()` 申请。 |
| `NOT_CONNECTED` | 目标卡片或智能体没有通过箭头与你的卡片相连。 | 请用户画一条箭头。 |
| `NOT_FOUND` | 没有这张卡片、智能体、键、文件或端口。 | |
| `QUOTA_EXCEEDED` | 某项配额已用完：存储字节数或键数、创建的卡片、文件监视器、智能体已满的提示词队列。 | 删除旧数据、停止旧监视器、稍后再试。 |
| `RATE_LIMITED` | 调用过于频繁。`data.retryAfterMs` 说明需要等多久。 | 合并、去抖或退避。（标题、状态、徽章、概览和提醒永远不会因此被拒绝——SDK 会合并并重试它们。） |
| `TOO_LARGE` | 消息、值或响应超出限制。 | 参见[限制](#limits)。 |
| `TIMEOUT` | 未能及时得到回应（端口请求、命令、网络请求）。 | |
| `BUDGET_PAUSED` | 工作区已超出预算；程序发出的提示词会被拒绝。 | 由用户在[预算](https://docs.neurosquad.ai/zh/cards/budget)卡片中提高上限。 |
| `BUSY` | 智能体正处于一轮中，而你指定了 `whenBusy: 'fail'`。 | |
| `HOST_NOT_ALLOWED` | `net.fetch` 访问的主机不在授权范围内，或解析到了被屏蔽的地址。 | 把主机加入 `network` 权限。 |
| `NETWORK_ERROR` | DNS、连接、TLS 或流失败。 | |
| `FS_DENIED` | 路径在工作区文件夹之外、在 `.git/` 之内，或经过了指向外部的链接。 | 使用相对路径。 |
| `FS_ERROR` | 其他任何文件问题；`ifMtimeMs` 不匹配时带有 `data.conflict`。 | |
| `NOT_VISIBLE` | 需要卡片在屏幕上：对话框、链接、聚焦、权限申请、发给危险模式智能体的提示词。 | 在 `card.visibility === 'visible'` 时重试。 |
| `USER_CANCELLED` | 用户拒绝了（确认框、发给危险模式智能体的提示词），或调用被取消。 | |
| `UNAVAILABLE` | 目标未在运行、工作区未打开、卡片已暂停，或连接已关闭。 | |
| `PROTOCOL_MISMATCH` | 卡片是为比应用更新的协议开发的。 | 由用户更新 NeuroSquad。 |
| `NOT_READY` | 在握手完成之前就发起了调用。 | 等待 `connect()` 完成。 |
| `INTERNAL` | 应用中的 bug。 | 附上卡片日志报告问题。 |

## 限制

所有限制都在 `card.limits` 中（SDK 的 `LIMITS` 常量）。SDK 会在发送前检查容易检查的那些；应用会强制执行全部限制。

| 方面 | 限制 |
| --- | --- |
| **消息** | 每条 ≤ 1 MB（`fs.write` 和 `net.fetch` 请求，以及 `fs.read`、`fs.list`、`net.fetch` 响应：≤ 12 MB）；同时进行中的调用 ≤ 64 个（超出的由 SDK 排队）；每秒 200 次调用，突发 400 次；值的嵌套 ≤ 64 层、≤ 200 000 个节点 |
| **卡片包** | 压缩包 ≤ 50 MB；解压后 ≤ 100 MB；≤ 5 000 个文件；每个 ≤ 20 MB；路径 ≤ 240 个字符、20 层；清单 ≤ 256 KB；图标 ≤ 128 KB |
| **清单** | ≤ 40 个设置；≤ 16 个输入和 16 个输出；≤ 32 个工具；≤ 32 个网络主机；schema ≤ 500 个节点、16 层，`enum` ≤ 256 个选项和 16 KB，`const` ≤ 4 KB |
| **存储** | 键 ≤ 256 个字符；值 ≤ 1 MB；≤ 10 000 个键；每张卡片 5 MB，每个卡片包 20 MB |
| **网络** | 请求体 ≤ 5 MB；响应 ≤ 10 MB；同时 6 个；每分钟 120 个；≤ 5 次重定向；超时 30 秒（最长 120 秒），包括读取正文；≤ 4 个流，每个在 5 分钟无数据或达到 256 MB 后关闭 |
| **文件** | 读写 ≤ 10 MB；列出 ≤ 5 000 项；≤ 20 个监视器 |
| **智能体** | 提示词 ≤ 20 000 个字符，每张卡片每分钟 6 条（方法和端口合并计数），每个智能体排队 ≤ 10 条；命令 ≤ 20 000 个字符；每张卡片每分钟 30 条命令（`run` 和终端端口合并计数，超时 ≤ 120 秒），`write` 每分钟 60 次；屏幕 ≤ 500 行；输出每 100 毫秒或每 64 KB 投递一次 |
| **工具** | 结果 ≤ 1 MB；超时 30 秒（最长 120 秒）；进度每秒 4 次 |
| **端口** | 每个输出每秒 20 条消息；保留值 ≤ 256 KB；请求超时 30 秒（最长 120 秒） |
| **卡片 UI** | 标题 ≤ 120（每分钟 30 次）；状态 ≤ 80，状态/徽章/概览各每分钟 120 次；概览每行 ≤ 160；提示条 ≤ 280（每 2 秒一条）；确认文本 ≤ 1 000（每分钟 10 次）；≤ 12 个菜单项（每分钟 30 次修改）；`settings.set` 每分钟 60 次；`tools.setEnabled` 每分钟 30 次；`usage.summary` 每分钟 6 次；提醒每 10 秒；聚焦每 5 秒；调整大小每 500 毫秒；≤ 4 张创建的卡片；剪贴板每秒一次、≤ 1 MB |
| **日志** | 每行 ≤ 2 000 个字符；每秒 50 行 |
| **页面** | 整个应用同时运行的卡片页面 ≤ 24 个；其中后台运行的 ≤ 8 个；隐藏 60 秒后暂停，有 1 秒时间保存；心跳每 5 秒，15 秒无响应显示“not responding”；启动后 10 秒内必须就绪 |
