Web Tools 错误码
本文定义内置 web tools(web_search / fetch_content / get_search_content)的结构化错误码。工具 API 见 web-tools.md,provider 行为见 web-providers.md,配置见 configuration.md。
Canonical source:
- 完整错误码清单以
src/modules/web/errors.ts中的WEB_ERROR_CODES为准。 - 实际返回结构参考
src/modules/web/types.ts的WebToolError。 - 具体返回路径参考
src/modules/web/search.ts、src/modules/web/fetch.ts、src/modules/web/storage.ts、src/modules/web/providers/select-provider.ts。 - 如果 README / README.zh 与本文档不一致,以本文档和源码为准。README 只保留常见错误说明,不作为完整错误码清单。
错误返回结构:
json
{
"error": {
"code": "ERROR_CODE",
"message": "Human-readable error message"
}
}message 是面向调用方的可操作提示,可能随版本优化;自动化逻辑应优先使用 code。
状态定义
| Status | 含义 |
|---|---|
| active | 当前有直接返回路径 |
| reserved | 已在 WEB_ERROR_CODES 中定义,但当前没有直接返回路径;保留给未来稳定细化 |
| deprecated | 旧名称或历史文档名称,不再作为 canonical code 返回 |
当前 canonical 错误码清单
下表覆盖 WEB_ERROR_CODES 中当前定义的全部错误码。
| Error code | Status | Meaning | Typical cause | Returned by | Retryable | Related source |
|---|---|---|---|---|---|---|
INVALID_INPUT | active | 通用输入或 provider 配置无效 | 缺少 url/responseId;不支持的 provider;显式 provider 未启用或缺少 endpoint | fetch_content、get_search_content、provider selection | 否 | fetch.ts、storage.ts、providers/select-provider.ts |
NOT_FOUND | active | 已存储结果或 selector 未命中 | responseId 不存在;urlIndex/queryIndex 越界;指定 url/query 不存在 | get_search_content | 否 | storage.ts |
WEB_SEARCH_FAILED | active | 搜索失败的兜底错误 | provider 抛出未分类错误;provider 响应解析失败;auto mode 没有 provider 成功完成 | web_search、provider selection | 视情况;源码 recovery 建议为 fallback | errors.ts、search.ts、providers/select-provider.ts |
WEB_SEARCH_TIMEOUT | active | 搜索超时或被 abort | provider 请求超时;调用被 AbortSignal 中止 | web_search | 是 | errors.ts、search.ts、abort.ts |
WEB_SEARCH_NO_RESULTS | reserved | 预留:搜索无结果 | 当前设计中"无结果"是成功响应:results = [],不是错误 | 当前不直接返回 | 否 | errors.ts、providers |
WEB_SEARCH_INVALID_QUERY | active | 查询为空或无有效内容 | query 缺失,或 query/queries trim 后为空 | web_search | 否 | search.ts |
CONTENT_FETCH_FAILED | active | 内容抓取/提取失败的兜底错误 | URL 安全策略拒绝;HTTP 非 2xx;不支持内容类型;二进制内容;重定向异常;Jina 请求异常;queue full 等未分类 fetch 错误 | fetch_content | 通常否;取决于 message | fetch.ts、security.ts、handlers.ts、concurrency.ts |
CONTENT_FETCH_TIMEOUT | active | 内容抓取超时或被 abort | 主 fetch 请求或 Jina 请求超时/被中止 | fetch_content | 是 | errors.ts、fetch.ts、abort.ts |
CONTENT_FETCH_INVALID_URL | active | URL 格式或协议无效 | URL 无法被 new URL() 解析;协议不是 HTTP/HTTPS | fetch_content | 否 | fetch.ts、security.ts |
CONTENT_FETCH_TOO_LARGE | reserved | 预留:响应体过大 | 当前实现使用 maxResponseBytes / maxContentChars 截断,不把截断视为错误 | 当前不直接返回 | 否 | errors.ts、fetch.ts |
PROVIDER_RATE_LIMITED | active | provider 限流 | provider 返回 HTTP 429 | web_search | 是 | errors.ts、search.ts、providers |
PROVIDER_UNAVAILABLE | active | provider 临时不可用 | provider 返回 HTTP 5xx | web_search | 是 | errors.ts、search.ts、providers |
PROVIDER_AUTH_FAILED | active | provider 认证失败 | API key 缺失或无效;HTTP 401/403 | web_search | 否 | errors.ts、search.ts、providers |
NETWORK_ERROR | active | 搜索 provider 网络连接错误 | fetch failed、DNS ENOTFOUND、ECONN* 等 | web_search | 是 | errors.ts、search.ts |
PARSE_ERROR | reserved | 预留:解析失败 | 当前 provider JSON parse/response shape 异常通常归入 WEB_SEARCH_FAILED;content handler 解析失败通常 fallback 并设置 parseWarning | 当前不直接返回 | 否 | errors.ts、providers、handlers.ts |
CACHE_ERROR | reserved | 预留:cache 操作失败 | 当前 search cache 是 best-effort,本地 cache/storage 超限通过淘汰或截断处理 | 当前不直接返回 | 否 | errors.ts、cache.ts、storage.ts |
六个预留/边界错误码的处理结论
| Error code | 当前结论 | 是否直接返回 | 说明 |
|---|---|---|---|
WEB_SEARCH_NO_RESULTS | 保留为 reserved | 否 | 当前语义稳定为成功空结果,不应把 results = [] 改成错误。 |
WEB_SEARCH_INVALID_QUERY | 保留并启用 | 是 | 空 query 是稳定、可测试的输入错误,直接返回该 code。 |
CONTENT_FETCH_INVALID_URL | 保留并启用 | 是 | URL 解析失败和非 HTTP/HTTPS 协议可稳定区分,直接返回该 code。 |
CONTENT_FETCH_TOO_LARGE | 保留为 reserved | 否 | 当前实现截断读取/输出,不把"过大但已截断"视为失败。 |
PARSE_ERROR | 保留为 reserved | 否 | 当前解析失败多为 fallback 或 provider 兜底错误,暂不引入跨 provider 解析层级。 |
CACHE_ERROR | 保留为 reserved | 否 | 当前 cache/storage 不作为用户可感知失败路径暴露。 |
按场景说明
web_search 输入与无结果
- 空 query 或 trim 后无有效 query:返回
WEB_SEARCH_INVALID_QUERY。 - provider 返回空结果:工具成功返回,结果为
results = [],不返回WEB_SEARCH_NO_RESULTS。 WEB_SEARCH_NO_RESULTS仅作为未来可能改变无结果语义时的 reserved code。
Provider 配置、认证与请求失败
- 显式 provider 不支持、未启用或 endpoint 配置无效:
INVALID_INPUT。 - API key 缺失、HTTP 401/403:
PROVIDER_AUTH_FAILED。 - HTTP 429:
PROVIDER_RATE_LIMITED。 - HTTP 5xx:
PROVIDER_UNAVAILABLE。 - 网络连接错误:
NETWORK_ERROR。 - provider JSON parse 或响应 shape 异常:当前继续归入
WEB_SEARCH_FAILED,暂不直接返回PARSE_ERROR。对当前用户来说,这类异常与普通 provider 失败的处理动作基本一致;未来如果 structured parser、convert_content或强 schema 校验变复杂,再启用PARSE_ERROR。
fetch_content URL 与安全策略
- 缺少
url/urls:INVALID_INPUT。 - URL 格式非法,或协议不是 HTTP/HTTPS:
CONTENT_FETCH_INVALID_URL。 fetch_content的 URL 校验/安全边界可能拒绝 localhost、私网地址、私有 hostname、DNS 解析到私网地址、非允许协议等 URL。- localhost/private IP、私有 hostname、DNS 解析到私网地址等安全策略拒绝:继续归入
CONTENT_FETCH_FAILED。这类失败不是"URL 格式无效",而是安全边界拒绝;当前不新增独立错误码。未来如果调用方需要区分普通 fetch 失败和安全策略拒绝,再考虑新增类似 CONTENT_FETCH_BLOCKED_BY_SECURITY_POLICY 或 CONTENT_FETCH_BLOCKED 的 canonical code。
fetch_content 内容类型与大小限制
- PDF、Office、ZIP、图片、音视频、可执行文件、magic bytes 检测到二进制内容:当前归入
CONTENT_FETCH_FAILED。对于 PDF、Office 等文档格式,错误信息可能提示下一步改用convert_content。 maxResponseBytes和maxContentChars当前用于截断读取/输出;截断结果通过truncated: true表示,不返回CONTENT_FETCH_TOO_LARGE。- 当前保持"截断成功"的语义:
fetch_content面向 agent 阅读,截断内容通常比直接失败更有用。 - 如果未来增加 strict/full mode 或
allowTruncate=false,可启用 reserved codeCONTENT_FETCH_TOO_LARGE。
Extraction / handler failure
- content handler 解析失败时优先 fallback 为纯文本,并设置
parseWarning。 - 未分类异常由
fetch_content汇总为CONTENT_FETCH_FAILED。 - 当前不直接返回
PARSE_ERROR,避免把可恢复的解析 fallback 变成用户可见错误。
Cache / storage
get_search_content未命中:NOT_FOUND。- search cache 当前是 best-effort;关闭 cache 是正常配置,不是错误。
- storage 超出限制通过淘汰或截断处理,不返回
CACHE_ERROR或STORAGE_FULL。
Concurrency / connection pool
- queue full 当前继续归入
CONTENT_FETCH_FAILED或WEB_SEARCH_FAILED,不新增QUEUE_FULL/CONCURRENCY_LIMITED。 - connection pool / fetch 底层异常会按调用路径归入
CONTENT_FETCH_FAILED、WEB_SEARCH_FAILED或NETWORK_ERROR。
Jina fallback
- Jina fallback 是
fetch_content内部补救机制,不是用户直接选择的独立 provider。 - Jina 返回非 2xx 或空内容:fallback 为原始 HTML 结果,不返回错误。
- Jina timeout/abort:可能返回
CONTENT_FETCH_TIMEOUT。 - Jina 其他请求异常:可能归入
CONTENT_FETCH_FAILED。 - 当前不新增
JINA_*错误码;如未来 Jina 成为用户可显式选择/观测的 provider,再考虑细化。
HTTP 状态码映射
当前 mapHttpStatusToError() 用于 search provider 错误分类:
| Status | 映射到 | Retryable |
|---|---|---|
| 401 | PROVIDER_AUTH_FAILED | 否 |
| 403 | PROVIDER_AUTH_FAILED | 否 |
| 429 | PROVIDER_RATE_LIMITED | 是 |
| 500 | PROVIDER_UNAVAILABLE | 是 |
| 502 | PROVIDER_UNAVAILABLE | 是 |
| 503 | PROVIDER_UNAVAILABLE | 是 |
| 504 | PROVIDER_UNAVAILABLE | 是 |
| 其他 | WEB_SEARCH_FAILED | 依具体 recovery |
Recovery 动作说明
src/modules/web/errors.ts 为部分错误码定义了 recovery 建议:
| Action | 含义 |
|---|---|
retry | 稍后重试当前请求 |
fallback | 尝试其他 provider 或 Jina fallback |
skip | 跳过当前内容 |
abort | 配置或输入错误,通常不应自动重试 |
并非所有实际返回的 WebToolError 都携带 recovery 字段;当前 tool 返回结构只保证 error.code 和 error.message。
Phase 6 的 web/convert 联动明确保持 message-based follow-up guidance。fetch_content 对疑似文档格式可以在 error.message 中提到 convert_content,但不公开 suggestion、nextAction、suggestedTool 等字段。只有当多个模块都需要统一的结构化建议时,才应新增 shared structured suggestion schema。
Deprecated / not canonical names
以下名称不是当前 canonical code,不应在 README 或用户文档中写成已实现专用 code:
FETCH_CONTENT_FAILED:deprecated 旧名称;当前 canonical code 是CONTENT_FETCH_FAILED。CONTENT_TOO_LARGE:deprecated/旧文档名称;当前 canonical reserved code 是CONTENT_FETCH_TOO_LARGE。STORAGE_FULL:未实现;当前 storage 使用条目上限淘汰和内容截断。CACHE_DISABLED:未实现;关闭 cache 是正常配置。JINA_TIMEOUT/JINA_FAILED:未实现;当前没有独立 Jina 错误码。QUEUE_FULL/CONCURRENCY_LIMITED:未实现;queue full 不作为独立 web error code 暴露。
Future hardening
- 如需更强类型约束,
WebToolError.error.code已可与WebErrorCode对齐;外部 JSON 结构仍保持字符串兼容。 - 如果未来 provider 统一抛出可识别的 parse/shape 错误,或 structured parser /
convert_content/ 强 schema 校验变复杂,可将该类错误从WEB_SEARCH_FAILED细化为PARSE_ERROR。 - 如果未来
fetch_content增加 strict/full mode 或allowTruncate=false,可启用CONTENT_FETCH_TOO_LARGE。 - 如果未来调用方需要区分普通 fetch 失败和安全策略拒绝,可新增类似 CONTENT_FETCH_BLOCKED_BY_SECURITY_POLICY 或 CONTENT_FETCH_BLOCKED 的 canonical code。
- 如果未来 cache/storage 失败成为用户可感知错误,可启用
CACHE_ERROR。