jaegertracing/jaeger · error

invalid OTLP proxy target %q: %w

Error message

invalid OTLP proxy target %q: %w

What it means

registerOTLPProxy configures the reverse proxy that forwards OTLP ingestion requests from the query server to a target collector endpoint. Before building the httputil.ReverseProxy it calls url.Parse on the configured target string; if that string is not a parseable URL the registration fails fast with this wrapped error. The intent is to surface a misconfigured proxy target at startup rather than at first request time.

Source

Thrown at cmd/jaeger/internal/extension/jaegerquery/internal/server.go:369

			}
		}
		return true
	}
}

func registerMCPTools(r *http.ServeMux, querySvc *querysvc.QueryService, tenancyMgr *tenancy.Manager, basePath string, cfg mcptools.Config, telset telemetry.Settings) {
	handler := mcptools.NewHandler(telset, querySvc, tenancyMgr, cfg)
	prefix := strings.TrimSuffix(basePath, "/") + "/api/ai/mcp"
	r.Handle(prefix+"/", http.StripPrefix(prefix, handler))
	telset.Logger.Info("Jaeger telemetry MCP endpoint enabled", zap.String("path", prefix+"/"))
}

// per-route wrap is the only instrumentation layer.
func registerOTLPProxy(r *http.ServeMux, queryOpts *QueryOptions, telset telemetry.Settings) error {
	cfg := queryOpts.OTLPProxy.Get()
	target, err := url.Parse(cfg.Target)
	if err != nil {
		return fmt.Errorf("invalid OTLP proxy target %q: %w", cfg.Target, err)
	}
	proxy := httputil.NewSingleHostReverseProxy(target)
	prefix := otlpProxyPathPrefix(queryOpts.BasePath)
	instrumented := otelhttp.NewHandler(
		http.StripPrefix(prefix, proxy),
		"otlp.proxy",
		otelhttp.WithTracerProvider(nooptrace.NewTracerProvider()),
		otelhttp.WithMeterProvider(telset.MeterProvider),
	)
	r.Handle(prefix+"/v1/", instrumented)
	telset.Logger.Info("OTLP proxy registered",
		zap.String("path_prefix", prefix+"/v1/"),
		zap.String("target", cfg.Target))
	return nil
}

func createHTTPServer(
	ctx context.Context,

View on GitHub (pinned to 806f444784)

Solutions

  1. Set the OTLP proxy target to a fully parseable URL, including scheme, e.g. http://localhost:4318 or https://collector:4318
  2. Inspect the quoted target in the error message for hidden whitespace, newlines, or unescaped IPv6 brackets and fix or remove them
  3. If the target comes from an env var or config file, echo/printf it and pipe through a URL validator before starting the server

Example fix

// before
otlp-proxy:
  target: "localhost:4318["
// after
otlp-proxy:
  target: "http://localhost:4318"
Defensive patterns

Strategy: validation

Validate before calling

// validate before passing to the query options
func validOTLPProxyTarget(target string) error {
	u, err := url.Parse(target)
	if err != nil {
		return fmt.Errorf("invalid target %q: %w", target, err)
	}
	if u.Scheme != "http" && u.Scheme != "https" {
		return fmt.Errorf("target %q must be an http(s) URL", target)
	}
	if u.Host == "" {
		return fmt.Errorf("target %q missing host", target)
	}
	return nil
}

Prevention

When it happens

Trigger: Starting the jaeger-query server with the OTLP proxy enabled (queryOptions.OTLPProxy.Target set) while cfg.Target cannot be parsed by net/url.Parse — e.g. "localhost:4318" with stray characters, "http://[bad-ipv6", or a value containing control characters or raw spaces.

Common situations: Typing the target into YAML/CLI config without the scheme and quoting it incorrectly; pasting a URL with trailing whitespace or an unescaped bracket in an IPv6 literal; setting the value via an env var that contains newlines; mixing up the OTLP gRPC host:port form (host:port) with the HTTP URL form the proxy expects.

Understand the failure class

Background: "Invalid URL" / "URL cannot be empty": fix the malformed or missing URL behind request-construction failures — this error's family across 50 libraries.

Related errors


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