Hmbown/CodeWhale · error

unsupported Z.AI web-search endpoint

Error message

unsupported Z.AI web-search endpoint: {base_url}

What it means

The Z.AI web-search adapter maps the configured base URL to the upstream search_engine parameter: api.z.ai maps to "search-prime" and open.bigmodel.cn maps to "search_std". Any other (or unrecognized) base URL has no known engine mapping, so build_body refuses the request instead of guessing an engine.

Solutions

  1. Set the provider base URL to exactly https://api.z.ai/api/paas/v4 or https://open.bigmodel.cn/api/paas/v4
  2. If using a proxy, add its normalized URL to the match arms in build_body with the correct search_engine
  3. Fix typos/extra path segments in the configured base URL
  4. Extend the mapping if Z.AI added a new official endpoint

Example fix

// before
_ => bail!("unsupported Z.AI web-search endpoint: {base_url}"),
// after: also accept a self-hosted proxy mapped to the standard engine
"https://zai-proxy.internal.example/api/paas/v4" => "search-prime",
_ => bail!("unsupported Z.AI web-search endpoint: {base_url}"),
Defensive patterns

Strategy: validation

Validate before calling

const SUPPORTED: [&str; 2] = ["https://api.z.ai/api/paas/v4", "https://open.bigmodel.cn/api/paas/v4"];
assert!(SUPPORTED.contains(&base_url.trim_end_matches('/').to_ascii_lowercase().as_str()),
        "unsupported Z.AI endpoint: {base_url}");

Try / catch

match build_body(&req, base_url) {
    Err(e) if e.to_string().contains("unsupported Z.AI web-search endpoint") => {
        eprintln!("{e}; defaulting to https://api.z.ai/api/paas/v4");
        build_body(&req, "https://api.z.ai/api/paas/v4")
    }
    other => other,
}

Prevention

When it happens

Trigger: build_body receives a base_url that, after trimming trailing slashes and lowercasing, matches neither "https://api.z.ai/api/paas/v4" nor "https://open.bigmodel.cn/api/paas/v4" — e.g. a custom proxy URL or a regional endpoint.

Common situations: Pointing the Z.AI provider at a self-hosted proxy or gateway URL; typo in the base URL; using a new Z.AI regional endpoint not yet in the mapping; trailing path differences like /api/paas/v4/ vs configured variants.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/a0e5a5c3a4291dea. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/client/provider_native_search/zai.rs:15

//! Z.AI and Zhipu structured Web Search API contracts.

use anyhow::{Result, bail};
use serde_json::{Value, json};

use super::{
    ProviderNativeSearchRequest, ProviderNativeSearchResponse, citation_from_url, push_citation,
};

pub(super) fn build_body(request: &ProviderNativeSearchRequest, base_url: &str) -> Result<Value> {
    let normalized = base_url.trim().trim_end_matches('/').to_ascii_lowercase();
    let search_engine = match normalized.as_str() {
        "https://api.z.ai/api/paas/v4" => "search-prime",
        "https://open.bigmodel.cn/api/paas/v4" => "search_std",
        _ => bail!("unsupported Z.AI web-search endpoint: {base_url}"),
    };
    Ok(json!({
        "search_engine": search_engine,
        "search_query": request.query,
        "count": request.max_results,
    }))
}

pub(super) fn parse(payload: &Value) -> ProviderNativeSearchResponse {
    let mut citations = Vec::new();
    if let Some(results) = payload.get("search_result").and_then(Value::as_array) {
        for result in results {
            let Some(url) = result.get("link").and_then(Value::as_str) else {
                continue;
            };
            let title = result
                .get("title")
                .and_then(Value::as_str)

View on GitHub (pinned to 73e0f67d83)