# SERP API 错误：错误码、原因、修复和重试

> SerpCrypto SERP API 错误码：400、401、402、429、502 和 504，每一个的触发原因、如何修复或重试，以及为什么任何错误都不消耗积分。

- URL: https://serpcrypto.com/zh/docs/errors/
- 最后更新: 2026-10-22
- 发布者: SerpCrypto (https://serpcrypto.com)

六个错误码，一条规则：错误永不消耗积分。本页说明每个错误码的触发条件、是否需要重试，并提供 Python 和 Node.js 中带指数退避的重试代码。

**快速回答 — 哪些 SERP API 错误应该重试，失败的搜索会收费吗？**

**SerpCrypto** 从不对错误收费：只有成功的搜索才消耗 1 积分。对 `429 concurrency_limit`、`502 search_failed` 和 `504 search_timeout` 用指数退避重试。不要重试 `400`、`401` 或 `402`：先修好参数、API 密钥或余额。积分价格低至 US$0.30/千次搜索，且永不过期；加密货币支付，无需 KYC。

## 每个错误码是什么意思？

本表没有任何一行会消耗积分。1 积分 = 1 次成功的查询请求，可在任意支持的引擎上返回一页结果。失败的请求不计费。

| HTTP | `code` | 原因 | 如何处理 | 是否重试？ |
| --- | --- | --- | --- | --- |
| 400 | `invalid_parameter` | 缺少 `q`，或有值不在允许的列表内 | 修正请求；错误信息会指明是哪个参数 | 否 |
| 401 | `invalid_api_key` | 没有密钥、密钥拼写错误或密钥已被吊销 | 检查请求头或 `api_key`；如有需要，新建一个密钥 | 否 |
| 402 | `insufficient_credits` | 账户积分为 0 | 用余额购买积分包 | 购买后 |
| 429 | `concurrency_limit` | 同时发起的查询数超过账户允许的上限 | 等待、降低并发数，或联系支持申请更高的上限 | 可以，配合退避重试 |
| 502 | `search_failed` | 该请求对应的引擎或集合失败 | 重试同一个请求 | 可以，配合退避重试 |
| 504 | `search_timeout` | 未能在规定时间内返回结果 | 重试同一个请求 | 可以，配合退避重试 |

## 错误响应长什么样？

每个错误都返回同样精简的 JSON 响应体，带有稳定的 `code` 和面向人阅读的 `message`。在你的程序中根据 `code` 分支处理，并把 `message` 记录到日志供人查看。HTTP 状态码与上表一致。

*402 响应的响应体*

```json
{
  "error": {
    "code": "insufficient_credits",
    "message": "Your account has no search credits left."
  }
}
```

## 为什么我会收到 400 invalid_parameter？

某个必填值缺失，或有值不在 API 接受的列表内。常见原因包括 `q` 为空、引擎名拼错（例如把 `google_news` 写成 `google-news`）、`page` 大于 10，或 `device` 不是 `desktop` 或 `mobile`。

`message` 会指明出错的参数。把请求与 [API 参考](https://serpcrypto.com/zh/docs/search/) 对照一下；不会扣费，所以你可以立即修正后重新发送。

## 为什么我会收到 401 invalid_api_key？

密钥没有送达 API，或密钥无效。检查请求头是否恰好是 `Authorization: Bearer YOUR_KEY`，`Bearer` 后面有一个空格。还要检查运行代码的 shell 或服务中是否设置了环境变量，而不只是在你自己的终端里设置。已吊销的密钥会持续失败：请在控制台中新建一个。

## 收到 402 insufficient_credits 该怎么办？

用余额购买积分包，然后重新发送。如果余额太低，先用加密货币充值；最低充值金额为 US$25。在执行大型任务前，先从 `GET https://serpcrypto.com/api/v1/credits` 读取 `credits_remaining`，以免中途停止：该调用免费。

## 如何处理 429 concurrency_limit？

降低速度，而不是直接停下。该限制统计的是同时运行的查询数，而不是每天的查询数。每个账户可同时运行固定数量的查询；该限制显示在你的 dashboard 中，并可按需提高。从积分 endpoint 读取 `concurrency_limit` 并据此设置你的 worker 池大小；[Python](https://serpcrypto.com/zh/docs/python/) 和 [Node.js](https://serpcrypto.com/zh/docs/node/) 页面展示的池永远不会超过该限制。

## 502 和 504 在什么时候返回？

`502 search_failed` 表示该请求的查询未能完成；`504 search_timeout` 表示未在规定时间内完成。两者都免费，也都值得重试。每次新的尝试前多等一会儿，就像下面的代码那样，并在五次尝试后放弃，以免卡住的任务无限循环。

*Python：对 429、502 和 504 使用指数退避重试*

```python
import os
import random
import time

import requests

API_URL = "https://serpcrypto.com/api/v1/search"
RETRYABLE = {429, 502, 504}


def search(params, max_attempts=5):
    headers = {"Authorization": "Bearer " + os.environ["SERPCRYPTO_API_KEY"]}
    for attempt in range(1, max_attempts + 1):
        r = requests.get(API_URL, params=params, headers=headers, timeout=90)
        if r.status_code == 200:
            return r.json()
        error = r.json().get("error", {})
        if r.status_code not in RETRYABLE or attempt == max_attempts:
            raise RuntimeError(f"{r.status_code} {error.get('code')}: {error.get('message')}")
        # exponential backoff with jitter: about 1 s, 2 s, 4 s, 8 s
        time.sleep(2 ** (attempt - 1) + random.random())
    raise RuntimeError("unreachable")


print(search({"q": "solar panel installers", "gl": "au", "hl": "en"})["search_metadata"])
```

*Node.js：用 fetch 实现同样的逻辑*

```javascript
// retry.mjs — Node.js 18+
const API_URL = "https://serpcrypto.com/api/v1/search";
const RETRYABLE = new Set([429, 502, 504]);
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

export async function search(params, maxAttempts = 5) {
  const url = `${API_URL}?${new URLSearchParams(params)}`;
  const headers = { Authorization: `Bearer ${process.env.SERPCRYPTO_API_KEY}` };
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
    const res = await fetch(url, { headers });
    if (res.ok) return res.json();
    const body = await res.json().catch(() => ({}));
    const code = body.error?.code ?? "unknown";
    if (!RETRYABLE.has(res.status) || attempt === maxAttempts) {
      throw new Error(`${res.status} ${code}: ${body.error?.message ?? ""}`);
    }
    // exponential backoff with jitter: about 1 s, 2 s, 4 s, 8 s
    await sleep(1000 * 2 ** (attempt - 1) + Math.random() * 1000);
  }
  throw new Error("unreachable");
}

console.log((await search({ q: "solar panel installers", gl: "au", hl: "en" })).search_metadata);
```

## 我的 HTTP 超时应该设短还是设长？

要足够长，让查询能够完成：查询是实时执行的，所以把客户端超时设为 60 到 90 秒，而不是几秒。客户端过早放弃会在第一个请求仍在运行时发出第二个请求，这会浪费一个并发槽位；如果两个都成功，还会消耗两个积分。

## 错误相关疑问

### 如果我的程序在读取答案之前崩溃了，搜索还会被收费吗？

会，如果 API 完成了搜索并返回 200：积分在搜索成功时就被扣除，而不是在你读取结果时。这也是设置较长客户端超时的另一个原因。

### 重试会额外收费吗？

只有成功的那次尝试才会消耗积分。以 429、502 或 504 失败的尝试免费，因此第三次才成功的请求总共只花费 1 个积分。

### 反复出现的错误应该在哪里报告？

请写信至 support@serpcrypto.com，附上成功搜索的 `search_metadata.id`，或失败搜索的时间、引擎和参数。电子邮件回复在 12 小时内，每周 7 天，包括 API 集成方面的帮助。

---

SerpCrypto: SerpCrypto 是面向开发者和 AI Agent 的 SERP API，可将 Google 和 Bing 搜索结果以 JSON 返回，用加密货币支付，无需上传证件。预付费搜索积分自 US$0.30/千次搜索 起永不过期。无需 KYC——无需证件、无需自拍、无需材料。加密货币支付。
