juanfont/headscale · error
%s creating confirm request: %w
Error message
%s creating confirm request: %w
What it means
`http.NewRequestWithContext` failed while building the POST that auto-submits the confirm form. This is Go's standard request constructor complaining about the assembled URL (scheme/host/path) or the body reader — the confirm URL built from `prevResp.Request.URL` plus the scraped form action was not parseable.
Source
Thrown at integration/scenario.go:1314
// Build the absolute POST URL from the response's request URL.
base := prevResp.Request.URL
confirmURL := &url.URL{
Scheme: base.Scheme,
Host: base.Host,
Path: formAction,
}
log.Printf("%s auto-submitting confirm form: %s", hostname, confirmURL)
formData := url.Values{
"headscale_register_confirm": {csrfToken},
}
ctx := context.Background()
req, err := http.NewRequestWithContext(ctx, http.MethodPost, confirmURL.String(), strings.NewReader(formData.Encode()))
if err != nil {
return "", nil, fmt.Errorf("%s creating confirm request: %w", hostname, err)
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
confirmResp, err := hc.Do(req)
if err != nil {
return "", nil, fmt.Errorf("%s sending confirm request: %w", hostname, err)
}
defer confirmResp.Body.Close()
confirmBytes, err := io.ReadAll(confirmResp.Body)
if err != nil {
return "", nil, fmt.Errorf("%s reading confirm response: %w", hostname, err)
}
if confirmResp.StatusCode != http.StatusOK {
return string(confirmBytes), nil, fmt.Errorf( //nolint:err113
"%s confirm returned status %d: %s",View on GitHub (pinned to 565fd254d0)
Solutions
- Log `confirmURL.String()` right before building the request and eyeball scheme/host/path.
- Sanitize the scraped action: `html.UnescapeString(formAction)` and `url.PathUnescape` as appropriate.
- Fall back to `base.ResolveReference(parsedAction)` instead of manually copying Scheme/Host/Path so relative actions resolve correctly.
Example fix
// before
confirmURL := &url.URL{Scheme: base.Scheme, Host: base.Host, Path: formAction}
// after
ref, err := url.Parse(html.UnescapeString(formAction))
if err != nil {
return "", nil, fmt.Errorf("%s confirm form: bad action URL %q: %w", hostname, formAction, err)
}
confirmURL := base.ResolveReference(ref) Defensive patterns
Strategy: validation
Validate before calling
// Validate the action before building the request.
ref, err := url.Parse(html.UnescapeString(formAction))
if err != nil || ref.Path == "" {
return "", nil, fmt.Errorf("%s confirm form: unusable action %q", hostname, formAction)
} Prevention
- HTML-unescape scraped URLs before parsing.
- Use base.ResolveReference for relative form actions.
- Unit-test the URL assembly with the known template output.
When it happens
Trigger: `confirmURL.String()` is malformed — e.g. the scraped `formAction` contains characters that make the URL invalid for `http.NewRequestWithContext`, or scheme/host are empty because `prevResp.Request` was nil-adjacent/mis-set.
Common situations: The form action scrape picked up garbage (HTML-escaped characters like &); a code path where `prevResp` is not the page that rendered the form; localhost URL built with an empty Host.
Related errors
- unknown --set value (want must|all)
- unexpected end of container wait
- no docker context found
- system checks failed
- test pattern is required as first argument or use --test fla
AI-assisted analysis of juanfont/headscale@565fd254d0 (2026-08-15).
Data as JSON: /api/errors/610d1aafca266174.
Report an issue: GitHub.