vectordotdev/vector · error

error creating request

Error message

error creating request

What it means

The apache_metrics source constructs a GET request per URL and unwraps Request::get(&url).body(Body::empty()) with expect("error creating request"). http::Request::builder only errors if the URI/method/headers are invalid, so this fires when a configured endpoint URL is not a valid URI.

Solutions

  1. Fix the endpoints entries in the apache_metrics source config to be valid absolute http(s) URLs.
  2. Validate URLs at config load time so bad endpoints are rejected during build rather than panicking at runtime.
  3. URL-encode any dynamic path/query components before configuring endpoints.

Example fix

// before
.expect("error creating request");
// after
let request = Request::get(&url)
    .body(Body::empty())
    .map_err(|e| warn!(message = "Skipping invalid endpoint.", endpoint = %sanitized_url, %e))?;
Defensive patterns

Strategy: validation

Validate before calling

url::Url::parse(&endpoint).map_err(|e| format!("invalid apache_metrics endpoint '{endpoint}': {e}"))?;

Try / catch

Request::get(&url).body(Body::empty()).map_err(|e| warn!(%e, "invalid endpoint"))?;

Prevention

When it happens

Trigger: An apache_metrics endpoint value in config that fails URI parsing or validation when applied to the request builder (invalid scheme, characters, or empty URL).

Common situations: Typo or unencoded characters in the endpoints config (spaces, unencoded unicode); endpoints list containing an empty string after templating/env substitution.

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 vectordotdev/vector@bdb87aeaa4 (2026-09-16). Data as JSON: /api/errors/971590e81cd284f1. Report an issue: GitHub.

Appendix: source

Thrown at src/sources/apache_metrics/mod.rs:163

    urls: Vec<http::Uri>,
    interval: Duration,
    namespace: Option<String>,
    shutdown: ShutdownSignal,
    mut out: SourceSender,
    proxy: ProxyConfig,
) -> super::Source {
    Box::pin(async move {
        let mut stream = IntervalStream::new(tokio::time::interval(interval))
            .take_until(shutdown)
            .map(move |_| stream::iter(urls.clone()))
            .flatten()
            .map(move |url| {
                let client = HttpClient::new(None, &proxy).expect("HTTPS initialization failed");
                let sanitized_url = url.to_sanitized_string();

                let request = Request::get(&url)
                    .body(Body::empty())
                    .expect("error creating request");

                let tags = metric_tags! {
                    "endpoint" => sanitized_url.to_string(),
                    "host" => url.sanitized_authority(),
                };

                let namespace = namespace.clone();
                client
                    .send(request)
                    .map_err(crate::Error::from)
                    .and_then(|response| async {
                        let (header, body) = response.into_parts();
                        let body = http_body::Body::collect(body).await?.to_bytes();
                        Ok((header, body))
                    })
                    .into_stream()
                    .filter_map(move |response| {
                        ready(match response {

View on GitHub (pinned to bdb87aeaa4)