# 错误

> 两种失败形态、reason 和 action 字段，以及 agent 在每种情况下该怎么做。

URL: https://mcp-docs.opennomos.com/zh/docs/reference/errors

OpenNomos 用两种不同的方式报告问题，因为它们的含义不同。

## 1. 被拒绝的调用

请求本身有错或不被允许。走 REST 时是带 JSON 正文的 HTTP 错误；走 MCP 时，工具结果带 `isError: true`，正文是同样的 JSON 文本。

```json
{ "message": "This tool requires the SEO & AI visibility pack", "code": "pack_required",
  "details": { "pack": "seo", "url": "https://tools.opennomos.com/console/packs", "action": "give_up_and_tell_user" } }
```

| `code` | HTTP | 含义和处理 |
| --- | --- | --- |
| `invalid_input` | 400 | 参数有误、缺失或未知（schema 是严格的，无法识别的键会被拒绝）。`message` 是发现的第一个问题。修正后重试。 |
| `invalid_request` | 400 | 其他错误请求的默认值（例如同时给了 `days` 和 `deadline`）。 |
| `unauthorized` | 401 | 完成 OAuth 或更换密钥。响应带有指向 OAuth 元数据的 `WWW-Authenticate`。 |
| `pack_required` | 403 | 工具包没有启用。告诉用户。 |
| `soft_limit` | 429 | 已达每月上游成本上限。告诉用户。 |
| `link_host_not_allowed` | 400 / 403 | 短链接的目标不是 https、是 IP 或短链服务，或者会成为第四个目标域名。 |
| `experiment_not_found`、`opportunity_not_found` | 404 | 这个 id 在该项目里不存在。 |
| `conflict` | 409 | 被并发修改了。再调一次。 |

写入或搜索触发频率限制时也会返回错误；放慢速度后重试。

## 2. 没有响应的来源

调用本身没问题，但上游来源给不出数据。这会作为**正常结果**（HTTP 200）返回，这样一个来源失败就不会掩盖其他来源：

```json
{ "error": "The source is rate limiting requests.", "reason": "rate_limited", "action": "retry_later", "retry_after_seconds": 30 }
```

在 [`search_signals`](https://mcp-docs.opennomos.com/zh/docs/tools/research/search_signals.md) 里，同样的字段出现在失败来源自己的条目里（`status: "unavailable"`），和成功的来源并列。

| `reason` | 含义 | `action` |
| --- | --- | --- |
| `rate_limited` | 来源在限流。可能带 `retry_after_seconds`。 | `retry_later` |
| `timeout` | 来源没有及时响应。 | `retry_later`，或 `try_other_tool` |
| `upstream_error` | 来源返回了错误。 | `retry_later`，或 `try_other_tool` |
| `invalid_input` | 来源拒绝了这个输入。检查参数。 | `give_up_and_tell_user` |
| `not_found` | 来源在这个地址或 id 上没有内容。 | `give_up_and_tell_user` |
| `upstream_account` | OpenNomos 自己访问该来源的通道出了问题（我们这边的凭据或余额）。重试没用。 | `give_up_and_tell_user` |
| `not_configured` | 这台服务器上没有配置该来源。 | `give_up_and_tell_user` |

| `action` | agent 该怎么做 |
| --- | --- |
| `retry_later` | 暂时性的。等一会儿（有 `retry_after_seconds` 就按它）再调一次同样的调用。 |
| `try_other_tool` | 同样的任务可以用 `tool` 里指明的工具完成（例如搜索结果页或新闻调用失败时，换 `search_signals`）。 |
| `give_up_and_tell_user` | 重试没用。如实告诉用户。 |

<Callout type="warn">
失败只表示来源没给出数据，**不**表示没有相关结果。千万不要因为一次调用失败，就得出“没人在讨论这件事”的结论。
</Callout>

## 条目偏少的结果

来源返回的条目比请求的少时，结果依然算成功，并带一句 `note`，例如：*Requested 10 organic results; the source returned 7. That is everything it returned (it may have no more matches, or may cap results).* `note` 只陈述观察到的事实。
