vxcontrol/pentagi · warning

telemetry endpoint is not set: %w

Error message

telemetry endpoint is not set: %w

What it means

NewTelemetryClient refuses to build the OTLP telemetry stack when cfg.TelemetryEndpoint is empty, wrapping the sentinel ErrNotConfigured. This is an intentional fast-fail: telemetry is optional and constructing exporters/providers without an endpoint would be meaningless.

Source

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

}

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)),
	)
	if err != nil {
		return nil, fmt.Errorf("failed to create telemetry connection: %w", err)
	}

	// Build all three exporters before creating any provider. Exporter creation
	// is the only remaining error path, and at that point no batch/reader
	// goroutine has started yet, so closing the connection is a complete teardown.

View on GitHub (pinned to ea665308ba)

Solutions

  1. Set the telemetry endpoint env var consumed by pkg/config (OTEL/telemetry endpoint, e.g. localhost:4317) in .env or docker-compose environment
  2. Or treat errors.Is(err, ErrNotConfigured) as 'skip telemetry' and continue without a client
  3. Regenerate .env from .env.example if the key is missing

Example fix

// before
client, err := NewTelemetryClient(ctx, cfg) // panics path if endpoint empty
// after
client, err := NewTelemetryClient(ctx, cfg)
if errors.Is(err, ErrNotConfigured) {
    log.Info("telemetry disabled: no endpoint configured")
    client = nil
} else if err != nil {
    return err
}
Defensive patterns

Strategy: validation

Validate before calling

if cfg.TelemetryEndpoint == "" {
    // telemetry disabled; don't call NewTelemetryClient
}

Try / catch

client, err := NewTelemetryClient(ctx, cfg)
if err != nil {
    if errors.Is(err, ErrNotConfigured) { return nil, nil } // optional feature
    return nil, err
}

Prevention

When it happens

Trigger: Calling NewTelemetryClient(ctx, cfg) with a *config.Config whose TelemetryEndpoint field is the empty string — e.g. the OTEL exporter endpoint env var was never set or config parsing left it blank.

Common situations: Running without the observability compose profile; .env missing the telemetry endpoint variable; installer wizard step skipped; tests exercising the not-configured path (TestNewTelemetryClient_EmptyEndpointReturnsErrNotConfigured).

Understand the failure class

Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.

Related errors


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