benbjohnson/litestream · error

create request: %w

Error message

create request: %w

What it means

HeartbeatClient.Ping() failed to construct the HTTP GET request to the configured heartbeat URL via http.NewRequestWithContext. This is rare in Go and almost always means the URL failed to parse (invalid scheme, control characters, malformed host). Ping returns early if URL is empty, so this only fires with a set but invalid URL.

Source

Thrown at heartbeat.go:52

	return &HeartbeatClient{
		URL:      url,
		Interval: interval,
		Timeout:  timeout,
		httpClient: &http.Client{
			Timeout: timeout,
		},
	}
}

func (c *HeartbeatClient) Ping(ctx context.Context) error {
	if c.URL == "" {
		return nil
	}

	req, err := http.NewRequestWithContext(ctx, http.MethodGet, c.URL, nil)
	if err != nil {
		return fmt.Errorf("create request: %w", err)
	}

	resp, err := c.httpClient.Do(req)
	if err != nil {
		return fmt.Errorf("http request: %w", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode < 200 || resp.StatusCode >= 300 {
		return fmt.Errorf("unexpected status code: %d", resp.StatusCode)
	}

	return nil
}

func (c *HeartbeatClient) ShouldPing() bool {
	c.mu.Lock()
	defer c.mu.Unlock()

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. Validate the heartbeat URL is a well-formed absolute URL with http:// or https:// scheme
  2. Check the config file for stray whitespace/newlines in the url value
  3. Test the URL with `curl -v '<url>'` to confirm it parses and is reachable
  4. If the URL is intentionally unset, leave it empty (Ping is a no-op then) rather than a malformed string

Example fix

# before
heartbeat:
  url: healthchecks.io/ping/abc123   # missing scheme

# after
heartbeat:
  url: https://healthchecks.io/ping/abc123
Defensive patterns

Strategy: validation

Validate before calling

if hb.URL != "" {
    if u, err := url.Parse(hb.URL); err != nil || u.Scheme == "" || u.Host == "" {
        return fmt.Errorf("invalid heartbeat url: %q", hb.URL)
    }
}

Try / catch

if err := hb.Ping(ctx); err != nil {
    if strings.Contains(err.Error(), "create request") {
        // malformed URL — fix config
    }
    return err
}

Prevention

When it happens

Trigger: Calling Ping() with c.URL set to a string that url.Parse rejects — e.g. missing scheme, embedded spaces or control characters, malformed percent-encoding, or a nil-request-inducing invalid method/URL combination.

Common situations: Typo in heartbeat URL in litestream.yml (missing http://); config expansion producing a URL with a trailing newline or spaces; shell interpolation injecting unexpected characters into the URL.

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 benbjohnson/litestream@4ed7a308f6 (2026-09-06). Data as JSON: /api/errors/e5b4768960fdd4b2. Report an issue: GitHub.