juanfont/headscale · error
test pattern is required as first argument or use --test fla
Error message
test pattern is required as first argument or use --test flag
What it means
Wrapped error from doLoginURLWithClient when hc.Do(req) fails: the login GET request could not be completed. Covers connection refused, DNS failure, TLS errors, redirects failing, and context cancellation. The hostname prefix says which node's login flow broke.
Source
Thrown at cmd/hi/run.go:15
package main
import (
"errors"
"fmt"
"log"
"os"
"path/filepath"
"strings"
"time"
"github.com/creachadair/command"
)
var ErrTestPatternRequired = errors.New("test pattern is required as first argument or use --test flag")
type RunConfig struct {
TestPattern string `flag:"test,Test pattern to run"`
Timeout time.Duration `flag:"timeout,default=120m,Test timeout"`
FailFast bool `flag:"failfast,default=true,Stop on first test failure"`
UsePostgres bool `flag:"postgres,default=false,Use PostgreSQL instead of SQLite"`
GoVersion string `flag:"go-version,Go version to use (auto-detected from go.mod)"`
CleanBefore bool `flag:"clean-before,default=true,Clean stale resources before test"`
CleanAfter bool `flag:"clean-after,default=true,Clean resources after test"`
KeepOnFailure bool `flag:"keep-on-failure,default=false,Keep containers on test failure"`
LogsDir string `flag:"logs-dir,default=control_logs,Control logs directory"`
Verbose bool `flag:"verbose,default=false,Verbose output"`
Stats bool `flag:"stats,default=false,Collect and display container resource usage statistics"`
HSMemoryLimit float64 `flag:"hs-memory-limit,default=0,Fail test if any Headscale container exceeds this memory limit in MB (0 = disabled)"`
TSMemoryLimit float64 `flag:"ts-memory-limit,default=0,Fail test if any Tailscale container exceeds this memory limit in MB (0 = disabled)"`
}
// runIntegrationTest executes the integration test workflow.View on GitHub (pinned to 565fd254d0)
Solutions
- Read the wrapped error: 'connection refused' means the target is not listening — check container status and port mapping.
- curl the login URL from the host to verify reachability and TLS.
- Ensure the OIDC provider container is healthy before starting the login flow.
- Re-run; transient Docker networking resets are common in CI.
Defensive patterns
Strategy: retry
Validate before calling
// cheap reachability check before the login GET
conn, err := net.DialTimeout("tcp", loginURL.Host, 2*time.Second)
if err != nil {
return fmt.Errorf("login target unreachable: %w", err)
}
conn.Close() Try / catch
resp, redir, err := doLoginURLWithClient(hostname, loginURL, hc, true)
if err != nil {
if strings.Contains(err.Error(), "sending http request") {
var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() {
// retry once after a short backoff
}
}
} Prevention
- Ensure headscale and the OIDC provider containers are healthy before login flows.
- Use host-resolvable server_url values in test configs.
- Retain full wrapped errors (never replace %w chains) so transport causes stay visible.
When it happens
Trigger: OIDC login against a login URL whose host is unreachable from the test process — headscale/OIDC provider container not listening, wrong hostname resolution, TLS certificate mismatch, or connection reset mid-request.
Common situations: Headscale container restarted between URL issuance and the GET, Docker network DNS flakiness, OIDC provider (e.g. dex) not yet ready, or the control server URL using a hostname only resolvable inside the Docker network.
Related errors
- not confirmed, aborting
- tag must start with the string 'tag:'
- unexpected end of container wait
- directory is required
- auth request rejected
AI-assisted analysis of juanfont/headscale@565fd254d0 (2026-08-15).
Data as JSON: /api/errors/0ad7ed348358f86c.
Report an issue: GitHub.