jaegertracing/jaeger · error

dial: %w

Error message

dial: %w

What it means

The ACP health check dials the agent's WebSocket endpoint (via DialWsAdapter) to verify the agent is reachable; if the dial fails the check returns "dial: <cause>". It exists so the jaegerquery AI extension can report agent connectivity as unhealthy instead of hanging or erroring obscurely later.

Source

Thrown at cmd/jaeger/internal/extension/jaegerquery/internal/jaegerai/aihealth/acp_check.go:44

// level errors are still returned to the caller from acp.SendRequest, so
// nothing diagnostic is lost.
var silentACPLogger = slog.New(slog.NewTextHandler(io.Discard, nil))

// NewACPCheck returns a check function that opens a fresh WebSocket
// connection to agentURL, performs one ACP `initialize` round-trip, and
// closes. Any transport-level or protocol-level error counts as unhealthy.
// Suitable for use as aihealth.Config.Check.
func NewACPCheck(agentURL string, agentHeaders configopaque.MapList, logger *zap.Logger) func(ctx context.Context) error {
	// The check only sends `initialize` and immediately closes — the sidecar
	// should never send a client-bound call in that window, but if it does we
	// refuse it rather than crash.
	noopMethodHandler := func(_ context.Context, method string, _ json.RawMessage) (any, *acp.RequestError) {
		return nil, acp.NewMethodNotFound(method)
	}
	return func(ctx context.Context) error {
		adapter, err := jaegerai.DialWsAdapter(ctx, agentURL, agentHeaders, logger)
		if err != nil {
			return fmt.Errorf("dial: %w", err)
		}
		defer adapter.Close()

		conn := acp.NewConnection(noopMethodHandler, adapter, adapter)
		conn.SetLogger(silentACPLogger)

		req := acp.InitializeRequest{
			ProtocolVersion: acp.ProtocolVersionNumber,
			ClientCapabilities: acp.ClientCapabilities{
				Fs:       acp.FileSystemCapabilities{ReadTextFile: false, WriteTextFile: false},
				Terminal: false,
			},
			ClientInfo: &acp.Implementation{
				Name:    "jaeger-ai-check",
				Version: version.Get().GitVersion,
			},
		}
		if _, err := acp.SendRequest[acp.InitializeResponse](conn, ctx, acp.AgentMethodInitialize, req); err != nil {

View on GitHub (pinned to 806f444784)

Solutions

  1. Verify the agent URL (scheme ws:// or wss://, host, port, path) in the AI extension config.
  2. Confirm the agent process is running and listening on that address (curl the endpoint / check its logs).
  3. If the dial fails with an HTTP error status, check the Jaeger log for 'WebSocket dial failed' with status/body to see auth or routing rejection details.
  4. Add required agent_headers (e.g. Authorization) if the agent requires auth.
Defensive patterns

Strategy: retry

Validate before calling

u, err := url.Parse(agentURL)
if err != nil || (u.Scheme != "ws" && u.Scheme != "wss") {
    return fmt.Errorf("invalid agent URL: %q", agentURL)
}

Try / catch

err := check(ctx)
if err != nil && strings.HasPrefix(err.Error(), "dial: ") {
    // do not tight-loop; back off and re-check agent availability
    time.Sleep(backoff)
    err = check(ctx)
}

Prevention

When it happens

Trigger: Health check runs and DialWsAdapter cannot establish the WebSocket: agent URL wrong, agent process down, TLS rejection, or the HTTP upgrade handshake returns a non-101 status.

Common situations: Agent not yet started when Jaeger boots; wrong port/path in the agent URL; missing agent_headers causing an auth-rejecting 401/403 on the upgrade request; network policy blocking the connection.

Related errors


AI-assisted analysis of jaegertracing/jaeger@806f444784 (2026-09-01). Data as JSON: /api/errors/0bddb188027c5b7c. Report an issue: GitHub.