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
- Prefix the endpoint with a scheme: use 'http://localhost:7280' or 'https://your-host' rather than 'localhost:7280'.
- Validate the endpoint with url::Url::parse(endpoint) before constructing the client and fail with a clear message.
- 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
- Always pass absolute http(s):// URLs as the endpoint.
- Validate the endpoint config at startup with Url::parse and a scheme check.
- Beware values like 'localhost:7280' — without a scheme Url treats 'localhost' as the scheme.
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
- topic `{}` does not exist
- node not found in pending
- OTP logs or traces do not support VRL transforms
- position of a Kafka partition should never be EOF
- position of a Kinesis shard should never be EOF
AI-assisted analysis of quickwit-oss/quickwit@a39730c5cd (2026-09-08).
Data as JSON: /api/errors/fbb2d90f2ddad306.
Report an issue: GitHub.