quickwit-oss/quickwit · error

root url should be well-formed

Error message

root url should be well-formed

What it means

The REST client constructor joins "api/v1/" onto the endpoint URL and asserts the result is a well-formed URL with expect. reqwest's Url::join only errors if the base URL cannot be a base (e.g. a non-hierarchical scheme like 'mailto:' or a relative URL), since 'api/v1/' is itself valid. A panic means the endpoint passed to RestClient::new was not an absolute HTTP(S) URL.

Source

Thrown at quickwit/quickwit-rest-client/src/rest_client.rs:67

struct Transport {
    base_url: Url,
    api_url: Url,
    client: ClientWithMiddleware,
}

impl Transport {
    fn new(
        endpoint: Url,
        connect_timeout: Timeout,
        ca_cert: Option<Certificate>,
        client_identity: Option<Identity>,
        num_retries: u32,
    ) -> Self {
        let base_url = endpoint;
        let api_url = base_url
            .join("api/v1/")
            .expect("root url should be well-formed");
        let mut reqwest_client_builder = ReqwestClientBuilder::new();
        if let Some(duration) = connect_timeout.as_duration_opt() {
            reqwest_client_builder = reqwest_client_builder.connect_timeout(duration);
        }
        if let Some(ca_cert) = ca_cert {
            reqwest_client_builder = reqwest_client_builder
                .tls_built_in_root_certs(false)
                .add_root_certificate(ca_cert);
        }
        if let Some(identity) = client_identity {
            reqwest_client_builder = reqwest_client_builder.identity(identity);
        }
        let retry_policy = ExponentialBackoff::builder()
            .retry_bounds(Duration::from_secs(1), Duration::from_mins(1))
            .build_with_max_retries(num_retries);
        let retry_transient_middleware = RetryTransientMiddleware::new_with_policy(retry_policy);
        let reqwest_client = reqwest_client_builder
            .build()

View on GitHub (pinned to a39730c5cd)

Solutions

  1. Prefix the endpoint with a scheme: use 'http://localhost:7280' or 'https://your-host' rather than 'localhost:7280'.
  2. Validate the endpoint with url::Url::parse(endpoint) before constructing the client and fail with a clear message.
  3. Check the config/env source for templating or trimming bugs that removed 'http(s)://'.

Example fix

// before
let client = RestClient::new("localhost:7280", ...);
// after
let endpoint = Url::parse("localhost:7280")
    .or_else(|_| Url::parse(&format!("http://{}", "localhost:7280")))?;
let client = RestClient::new(endpoint, ...);
Defensive patterns

Strategy: validation

Validate before calling

let parsed = url::Url::parse(endpoint).expect("valid absolute URL");
assert!(matches!(parsed.scheme(), "http" | "https"));

Prevention

When it happens

Trigger: Constructing a RestClient with an endpoint that is not a valid absolute base URL — e.g. 'localhost:7280' without a scheme parsed as scheme 'localhost', a URL like 'mailto:foo@bar', an empty string, or a config value with whitespace/typos such as 'http:/...' or 'http:/localhost:7280'.

Common situations: Misconfigured QW_REST_CLIENT endpoint env var or config file missing the 'http://' prefix; passing a relative path instead of a full URL when embedding the rest client in another tool; environment-specific config where the scheme was stripped by templating.

Understand the failure class

Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.

Related errors


AI-assisted analysis of quickwit-oss/quickwit@a39730c5cd (2026-09-08). Data as JSON: /api/errors/fbb2d90f2ddad306. Report an issue: GitHub.