{"record":{"id":"7e1a76c6099898f0","repo":"vxcontrol/pentagi","slug":"telemetry-endpoint-is-not-set-w","errorCode":null,"errorMessage":"telemetry endpoint is not set: %w","messagePattern":"telemetry endpoint is not set: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"backend/pkg/observability/otelclient.go","lineNumber":100,"sourceCode":"}\n\nfunc (c *telemetryClient) ForceFlush(ctx context.Context) error {\n\tvar errs []error\n\tif err := c.logger.ForceFlush(ctx); err != nil {\n\t\terrs = append(errs, fmt.Errorf(\"failed to force flush logger: %w\", err))\n\t}\n\tif err := c.meter.ForceFlush(ctx); err != nil {\n\t\terrs = append(errs, fmt.Errorf(\"failed to force flush meter: %w\", err))\n\t}\n\tif err := c.tracer.ForceFlush(ctx); err != nil {\n\t\terrs = append(errs, fmt.Errorf(\"failed to force flush tracer: %w\", err))\n\t}\n\treturn errors.Join(errs...)\n}\n\nfunc NewTelemetryClient(ctx context.Context, cfg *config.Config) (TelemetryClient, error) {\n\tif cfg.TelemetryEndpoint == \"\" {\n\t\treturn nil, fmt.Errorf(\"telemetry endpoint is not set: %w\", ErrNotConfigured)\n\t}\n\n\t// grpc.NewClient is non-blocking: it never dials during startup, so a\n\t// set-but-unreachable collector can't stall main(), and the connection is\n\t// established (and re-established) lazily in the background — a collector that\n\t// comes up after the app does connects on its own, without a restart.\n\tconn, err := grpc.NewClient(\n\t\tcfg.TelemetryEndpoint,\n\t\tgrpc.WithTransportCredentials(insecure.NewCredentials()),\n\t\tgrpc.WithDefaultCallOptions(grpc.WaitForReady(true)),\n\t)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create telemetry connection: %w\", err)\n\t}\n\n\t// Build all three exporters before creating any provider. Exporter creation\n\t// is the only remaining error path, and at that point no batch/reader\n\t// goroutine has started yet, so closing the connection is a complete teardown.","sourceCodeStart":82,"sourceCodeEnd":118,"githubUrl":"https://github.com/vxcontrol/pentagi/blob/ea665308baaff015b226f308438a68d929d0f29b/backend/pkg/observability/otelclient.go#L82-L118","documentation":"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.","triggerScenarios":"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.","commonSituations":"Running without the observability compose profile; .env missing the telemetry endpoint variable; installer wizard step skipped; tests exercising the not-configured path (TestNewTelemetryClient_EmptyEndpointReturnsErrNotConfigured).","solutions":["Set the telemetry endpoint env var consumed by pkg/config (OTEL/telemetry endpoint, e.g. localhost:4317) in .env or docker-compose environment","Or treat errors.Is(err, ErrNotConfigured) as 'skip telemetry' and continue without a client","Regenerate .env from .env.example if the key is missing"],"exampleFix":"// before\nclient, err := NewTelemetryClient(ctx, cfg) // panics path if endpoint empty\n// after\nclient, err := NewTelemetryClient(ctx, cfg)\nif errors.Is(err, ErrNotConfigured) {\n    log.Info(\"telemetry disabled: no endpoint configured\")\n    client = nil\n} else if err != nil {\n    return err\n}","handlingStrategy":"validation","validationCode":"if cfg.TelemetryEndpoint == \"\" {\n    // telemetry disabled; don't call NewTelemetryClient\n}","typeGuard":null,"tryCatchPattern":"client, err := NewTelemetryClient(ctx, cfg)\nif err != nil {\n    if errors.Is(err, ErrNotConfigured) { return nil, nil } // optional feature\n    return nil, err\n}","preventionTips":["Set the telemetry endpoint env var in .env from .env.example","Handle ErrNotConfigured as an intentional disabled state","Validate config at startup before wiring telemetry","Document that observability requires the observability compose profile"],"tags":["configuration","opentelemetry","env-var"],"backgroundTag":"missing-env-var","analyzedSha":"ea665308baaff015b226f308438a68d929d0f29b","analyzedAt":"2026-09-01T14:16:31.421Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}