vxcontrol/pentagi · error

failed to force flush tracer: %w

Error message

failed to force flush tracer: %w

What it means

This error is produced by telemetryClient.ForceFlush when the trace provider fails to force-flush pending spans. It is wrapped with context naming the tracer leg, joined with any logger/meter flush errors via errors.Join.

Source

Thrown at backend/pkg/observability/otelclient.go:93

	}
	// Always close the connection, even if a provider shutdown failed above, so a
	// stalled flush can't leak the grpc conn.
	if err := c.conn.Close(); err != nil {
		errs = append(errs, fmt.Errorf("failed to close telemetry connection: %w", err))
	}
	return errors.Join(errs...)
}

func (c *telemetryClient) ForceFlush(ctx context.Context) error {
	var errs []error
	if err := c.logger.ForceFlush(ctx); err != nil {
		errs = append(errs, fmt.Errorf("failed to force flush logger: %w", err))
	}
	if err := c.meter.ForceFlush(ctx); err != nil {
		errs = append(errs, fmt.Errorf("failed to force flush meter: %w", err))
	}
	if err := c.tracer.ForceFlush(ctx); err != nil {
		errs = append(errs, fmt.Errorf("failed to force flush tracer: %w", err))
	}
	return errors.Join(errs...)
}

func NewTelemetryClient(ctx context.Context, cfg *config.Config) (TelemetryClient, error) {
	if cfg.TelemetryEndpoint == "" {
		return nil, fmt.Errorf("telemetry endpoint is not set: %w", ErrNotConfigured)
	}

	// grpc.NewClient is non-blocking: it never dials during startup, so a
	// set-but-unreachable collector can't stall main(), and the connection is
	// established (and re-established) lazily in the background — a collector that
	// comes up after the app does connects on its own, without a restart.
	conn, err := grpc.NewClient(
		cfg.TelemetryEndpoint,
		grpc.WithTransportCredentials(insecure.NewCredentials()),
		grpc.WithDefaultCallOptions(grpc.WaitForReady(true)),
	)

View on GitHub (pinned to ea665308ba)

Solutions

  1. Read the joined/wrapped cause for the real exporter error
  2. Verify collector reachability at cfg.TelemetryEndpoint (port 4317)
  3. Use a longer-lived context for shutdown flushes
  4. Treat as non-fatal at shutdown: log and continue, since spans are typically advisory
Defensive patterns

Strategy: try-catch

Validate before calling

if client == nil { return } // telemetry never initialized

Try / catch

if err := client.ForceFlush(ctx); err != nil {
    log.Warnf("span flush failed (spans may be dropped): %v", err)
}

Prevention

When it happens

Trigger: Calling ForceFlush(ctx) while otlptracegrpc cannot export buffered spans: ctx deadline exceeded, collector unavailable, exporter returning a retryable/permanent export error.

Common situations: Graceful shutdown with a down or overloaded OpenTelemetry Collector; spans accumulated during a burst exceeding the flush timeout; DNS/network failures to the telemetry endpoint.

Related errors


AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01). Data as JSON: /api/errors/0b888e14574b1c62. Report an issue: GitHub.