jaegertracing/jaeger · error
failed to build transport pool: %w
Error message
failed to build transport pool: %w
What it means
newRawClient constructs the elastic-transport connection pool via elastictransport.NewClient (indirectly, through the newPool var). If the pool cannot be built, the error is wrapped as "failed to build transport pool" and construction of the raw client aborts. This is a constructor-time failure, so the client is unusable before any request is sent.
Source
Thrown at internal/storage/elasticsearch/esclient/transport.go:94
transportOpts := []elastictransport.Option{
elastictransport.WithURLs(urls...),
elastictransport.WithTransport(base),
elastictransport.WithDisableRetry(),
}
if opts.compressRequestBody {
// Defaults to gzip.DefaultCompression, matching the level the olivere
// client used before it was retired. The pool gzips the body and sets
// Content-Encoding before handing the request to base, so the auth stack
// below (notably the SigV4 signer) signs the compressed payload that
// actually goes on the wire.
transportOpts = append(transportOpts, elastictransport.WithCompression())
}
if opts.logLevel != "" && opts.logger != nil {
transportOpts = append(transportOpts, elastictransport.WithLogger(newZapLogger(opts.logLevel, opts.logger)))
}
pool, err := newPool(transportOpts...)
if err != nil {
return nil, fmt.Errorf("failed to build transport pool: %w", err)
}
rc := &rawClient{pool: pool, base: base}
if opts.discoverNodes {
// Node discovery (sniffing): query one seed node once at startup and add
// the cluster's other nodes to the pool. This is a one-shot call — no
// background goroutine is scheduled (that would require a discovery
// interval), so close() still has nothing to stop. Left off by default
// because a cluster that publishes addresses the client cannot reach (a
// common AWS/proxy setup) would break the pool. DiscoverNodesContext
// tolerates a nil ctx (it falls back to context.Background()).
if err := pool.DiscoverNodesContext(ctx); err != nil {
// The discovery request opened a connection through base; release it,
// since we are abandoning this client instead of returning it for the
// caller to Close.
rc.close()
return nil, fmt.Errorf("failed to discover Elasticsearch nodes (sniffing): %w", err)
}
}View on GitHub (pinned to 806f444784)
Solutions
- Inspect the wrapped inner error (%w) to see the pool's actual failure reason and fix the underlying cause.
- Verify all servers entries are absolute http(s) URLs with scheme and host (see the URL validation that runs just before pool construction).
- Reduce option complexity: retry is disabled by design, so check compression and logger options for bad values (e.g. invalid log level).
- If it persists with valid config, check the elastic-transport-go library version for known construction bugs.
Defensive patterns
Strategy: try-catch
Validate before calling
for _, s := range cfg.Servers {
u, err := url.Parse(s)
if err != nil || u.Scheme == "" || u.Host == "" {
return fmt.Errorf("pre-validate server %q failed", s)
}
} Try / catch
rc, err := esclient.NewClient(...)
if err != nil {
var poolErr *fmt.wrapError // inspect unwrapped chain for the pool's root cause
root := err
for errors.Unwrap(root) != nil { root = errors.Unwrap(root) }
return fmt.Errorf("elasticsearch client init failed: %w (root: %v)", err, root)
} Prevention
- Pre-validate all server URLs and option values before constructing the client.
- Keep the elastic-transport-go dependency current to avoid fixed construction bugs.
- Log the full error chain (errors.Unwrap loop) so the pool's root cause is visible in startup logs.
- Fail fast at config load time rather than at client construction to isolate config vs library issues.
When it happens
Trigger: Calling NewClient/newRawClient where the elastictransport.NewClient call with the configured URLs, base RoundTripper, retry/compression/logger options returns an error (e.g. no valid URLs after option processing).
Common situations: Misconfigured server lists that pass URL parsing but produce an empty/invalid URL set for the pool; defects or unusual option combinations in transport construction; test setups that substitute a failing newPool implementation.
Related errors
- file must begin with '['
- max spans count reached
- empty configuration
- at least one storage backend is required
- cannot assign unique span ID, too many spans in the trace
AI-assisted analysis of jaegertracing/jaeger@806f444784 (2026-09-01).
Data as JSON: /api/errors/d42244fd42d4e9ee.
Report an issue: GitHub.