searxng/searxng · error · SearxEngineAPIException

Invalid response

Error message

Invalid response

What it means

After parsing JSON, the engine validates the payload shape: it must be a dict containing a 'data' key. Anything else (e.g. a JSON error object like {'status':1,'msg':'...'} or a list) raises SearxEngineAPIException('Invalid response').

Source

Thrown at searx/engines/chinaso.py:117

    params["url"] = f"{base_url}/v5/general/v1/web/search?{urlencode(query_params)}"
    cookie = {
        "uid": base64.b64encode(secrets.token_bytes(16)).decode("utf-8"),
    }
    params["cookies"] = cookie

    return params


def response(resp):
    try:
        data = resp.json()
    except Exception as e:
        raise SearxEngineAPIException(f"Invalid response: {e}") from e

    # Upstream returns {'status': 0, 'msg': 'empty result', 'data': {}} when there
    # are no results; this is a valid empty result rather than an API error.
    if not isinstance(data, dict) or "data" not in data:
        raise SearxEngineAPIException("Invalid response")
    if not data["data"]:
        return []

    results = []
    if not data.get("data", {}).get("data"):
        raise SearxEngineAPIException("Invalid response")

    for entry in data["data"]["data"]:
        published_date = None
        if entry.get("timestamp"):
            try:
                published_date = datetime.fromtimestamp(int(entry["timestamp"]))
            except (ValueError, TypeError):
                pass

        results.append(
            {
                'title': html_to_text(entry["title"]),

View on GitHub (pinned to 9fea41204f)

Solutions

  1. Log the full JSON body to see the actual upstream error message in the envelope
  2. Retry with backoff if it indicates rate limiting
  3. Update the engine to handle/recognize the new error envelope or disable it if the contract changed
  4. Verify request parameters (headers, cookies) still match what the API expects
Defensive patterns

Strategy: validation

Validate before calling

data = resp.json()
if not isinstance(data, dict) or 'data' not in data:
    msg = data.get('msg') if isinstance(data, dict) else data
    logger.warning('chinaso error envelope: %s', msg)
    return []

Type guard

def is_chinaso_results_payload(data) -> bool:
    return (
        isinstance(data, dict)
        and isinstance(data.get('data'), dict)
        and isinstance(data['data'].get('data'), list)
    )

Try / catch

try:
    ...
except SearxEngineAPIException as e:
    if str(e) == 'Invalid response':
        # shape drift, inspect raw body
        ...

Prevention

When it happens

Trigger: ChinaSo returns a JSON object without a 'data' key — typically an API-level error envelope (rate limit, invalid parameters, blocked client) rather than a search result payload.

Common situations: API error envelope changed; query parameters the engine sends are no longer accepted; IP soft-banned returning {'msg': 'forbidden'} style responses.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of searxng/searxng@9fea41204f (2026-08-27). Data as JSON: /api/errors/6cece0e3f2470528. Report an issue: GitHub.