jaegertracing/jaeger · error

ai.agent_headers: %w

Error message

ai.agent_headers: %w

What it means

This error wraps the failure of AgentHeaders.Validate() during the jaegerquery AI extension config validation. MapList (the wire type for headers) permits repeated names, so a config with two entries for the same header name would silently keep only one value at runtime; validation rejects the config up front so the operator knows which setting is broken via the "ai.agent_headers:" prefix.

Source

Thrown at cmd/jaeger/internal/extension/jaegerquery/internal/flags.go:168

// (see the AIConfig type-level comment) so by the time Validate runs the
// caller's struct already has sensible values for any field they omitted.
func (c *AIConfig) Validate() error {
	if c.AgentURL == "" && !c.MCP.HasValue() {
		return errors.New("ai requires agent_url (AI chat) or mcp (telemetry MCP tools)")
	}
	if c.MaxRequestBodySize <= 0 {
		return errors.New("ai.max_request_body_size must be a positive integer")
	}
	if c.HealthCheckInterval < 0 {
		return errors.New("ai.health_check_interval must not be negative (0 disables the health checker)")
	}
	if c.HealthCheckInterval > 0 && c.HealthCheckTimeout <= 0 {
		return errors.New("ai.health_check_timeout must be positive when health_check_interval is positive")
	}
	// MapList permits repeated names on the wire; a duplicated header would
	// silently keep only one value, so reject it here rather than guess which.
	if err := c.AgentHeaders.Validate(); err != nil {
		return fmt.Errorf("ai.agent_headers: %w", err)
	}
	// MCPConfig.Validate is reached by the collector's config walk on its own,
	// the same way OTLPProxyConfig's is; delegating to it here would only
	// duplicate the check and drop the "mcp:" path segment from the message.
	return nil
}

// resolveMCPBaseURL returns the base URL the gateway announces for the turn-scoped
// MCP endpoint, or "" to announce no HTTP transport. An explicit base_url always
// wins. Otherwise the gateway infers its own loopback address, which requires every
// leg of the round trip to hold:
//
//   - The sidecar must be co-located: AgentURL is a loopback address, so the
//     sidecar shares this network namespace and its "localhost" is ours.
//   - The query server must actually be listening on loopback: a wildcard bind
//     (":16686", "0.0.0.0", "::") or a loopback bind. Bound to one specific
//     interface, say "10.0.0.5:16686", nothing answers on loopback.
//   - TLS must be off. A server certificate carries a SAN for the name operators

View on GitHub (pinned to 806f444784)

Solutions

  1. Remove the duplicate header entry from ai.agent_headers in your jaeger-query config, keeping the single correct value.
  2. If you need multiple values for one header, combine them into one entry (e.g. comma-joined value) where the target system allows it.
  3. Review how the config is assembled (env overlays, helm values, templates) to find what injects the duplicate.

Example fix

// before
agent_headers:
  - name: Authorization
    value: "Bearer x"
  - name: Authorization
    value: "Bearer y"
// after
agent_headers:
  - name: Authorization
    value: "Bearer x"
Defensive patterns

Strategy: validation

Validate before calling

names := map[string]bool{}
for _, h := range cfg.AgentHeaders {
    if names[h.Name] {
        return fmt.Errorf("duplicate agent header: %s", h.Name)
    }
    names[h.Name] = true
}

Prevention

When it happens

Trigger: Starting jaeger-all-in-one or jaeger-query with an AI config whose agent_headers map/list contains two entries with the same header name, e.g. agent_headers: [{name: Authorization, value: a}, {name: Authorization, value: b}].

Common situations: Operators merging YAML config fragments (e.g. base + overlay) so the same header appears twice; copy-pasting header blocks when adding auth and custom tracing headers; templating tools emitting duplicate keys.

Related errors


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