dapr/dapr · critical
failed to build HTTP client for %q: %w
Error message
failed to build HTTP client for %q: %w
What it means
Thrown by SessionHolder.connect when mcpauth.BuildHTTPClient fails while creating the HTTP client for the MCP server. BuildHTTPClient resolves the auth config on the MCPServer manifest: OAuth2 client credentials, OIDC discovery, mTLS/CA material from secret refs, and SPIFFE identity via the security handler. Since NewSessionHolder connects eagerly, this error surfaces at MCP-server registration time (analogous to component Init failure) and again on every reconnect attempt.
Source
Thrown at pkg/runtime/wfengine/inprocess/mcp/v1/session.go:149
if !h.closed.CompareAndSwap(false, true) {
return
}
h.lifecycleCancel()
h.mu.Lock()
defer h.mu.Unlock()
if s := h.session.Load(); s != nil {
(*s).Close()
h.session.Store(nil)
}
}
// connect builds an HTTP client, transport, and MCP session.
// The caller's context controls the connection deadline.
// The lifecycleCtx is passed separately for background work (token refresh) that must outlive the connect call.
func (h *SessionHolder) connect(ctx context.Context) (*mcp.ClientSession, error) {
httpClient, err := mcpauth.BuildHTTPClient(ctx, h.lifecycleCtx, h.server, h.store, h.sec)
if err != nil {
return nil, fmt.Errorf("failed to build HTTP client for %q: %w", h.server.Name, err)
}
transport, err := buildTransport(h.server, httpClient)
if err != nil {
return nil, fmt.Errorf("failed to build transport for %q: %w", h.server.Name, err)
}
workerLog.Debugf("connecting to MCP server %q", h.server.Name)
c := mcp.NewClient(&mcp.Implementation{Name: mcpClientName, Version: mcpClientVersion}, &mcp.ClientOptions{
KeepAlive: keepAliveInterval,
})
session, err := c.Connect(ctx, transport, nil)
if err != nil {
return nil, fmt.Errorf("failed to connect to MCP server %q: %w", h.server.Name, err)
}
return session, nil
}
View on GitHub (pinned to 74ad417027)
Solutions
- Check the wrapped error — BuildHTTPClient names the failing step (secret fetch, discovery, cert parse)
- Verify every secretKeyRef in the MCPServer manifest exists in the declared secret store (kubectl get secret / dapr components)
- From inside the daprd pod, curl the issuer/token endpoint to confirm reachability and valid TLS
- Validate the caCert/clientCert PEM blocks decode (openssl x509 -noout -text)
- Fix credentials if the wrapped error is an auth rejection from the identity provider
- Temporarily strip auth from the manifest to confirm connectivity, then re-add auth piecewise
Example fix
# before: secret ref that does not exist
spec:
endpoint:
streamableHTTP:
url: https://mcp.internal/tools
auth:
oauth2:
clientSecret:
secretKeyRef:
name: mcp-secrets
key: client-secret-typo
# after: key matches the actual secret entry
key: client-secret Defensive patterns
Strategy: retry
Validate before calling
// Pre-flight the auth surface before registering the MCPServer
func preflightAuth(ctx context.Context, srv *mcpserverapi.MCPServer, store *compstore.ComponentStore) error {
for _, ref := range collectSecretRefs(srv) {
if _, err := store.GetSecret(ctx, ref); err != nil {
return fmt.Errorf("secret %q unresolvable: %w", ref, err)
}
}
return nil
} Type guard
func isHTTPClientBuildFailure(err error) bool {
return err != nil && strings.Contains(err.Error(), "failed to build HTTP client")
} Try / catch
holder, err := NewSessionHolder(ctx, srv, store, sec)
if err != nil && isHTTPClientBuildFailure(err) {
// config errors are permanent; network blips during OIDC discovery are not —
// retry a bounded number of times before surfacing
for range 3 {
time.Sleep(2 * time.Second)
if holder, err = NewSessionHolder(ctx, srv, store, sec); err == nil { break }
if !isHTTPClientBuildFailure(err) { break }
}
}
if err != nil { return err } Prevention
- Dry-run secret refs against the real secret store before applying the manifest
- Keep the issuer/token endpoint reachable from the daprd pod (network policy, DNS, TLS CA)
- Rotate OAuth credentials with overlap and update the secret before restarting daprd
- Validate caCert PEM files in CI with openssl
When it happens
Trigger: MCPServer spec declares auth (e.g. endpoint.streamableHTTP with oauth2/static bearer via secretKeyRefs) and any of: the secret reference cannot be resolved from the configured secret store; the OIDC issuer/token endpoint is unreachable or returns invalid metadata; client credentials are rejected at discovery; caCert PEM is invalid; the security handler is required but unavailable.
Common situations: secretName/secretKey typo in the manifest; secret store component not loaded before the MCPServer; issuer URL blocked by network policy from the daprd pod; expired/rotated client secret; wrong tokenEndpoint URL; missing SPIFFE/SPIRE setup when workload identity is enabled.
Related errors
- OAuth2 credential retrieval failed: %w
- auth.oauth2.secretKeyRef is required for OAuth2 client crede
- secret fetch failed
- failed to get secret %q from store %q: %w
- SPIFFE JWT fetch failed: %w
AI-assisted analysis of dapr/dapr@74ad417027 (2026-08-16).
Data as JSON: /api/errors/0a00a420fcc43b87.
Report an issue: GitHub.