grpc/grpc-go · error

failed to register observability views: %v

Error message

failed to register observability views: %v

What it means

Returned when view.Register(defaultViews...) fails. OpenCensus's view.Register fails if any of the supplied views are already registered (duplicate name). This typically indicates Start() was invoked twice, or another package already registered the gRPC OpenCensus views.

Source

Thrown at gcp/observability/opencensus.go:146

		return nil
	}

	var err error
	exporter, err = newExporter(config)
	if err != nil {
		return err
	}

	var to opencensus.TraceOptions
	if config.CloudTrace != nil {
		to.TS = trace.ProbabilitySampler(config.CloudTrace.SamplingRate)
		trace.RegisterExporter(exporter.(trace.Exporter))
		logger.Infof("Start collecting and exporting trace spans with global_trace_sampling_rate=%.2f", config.CloudTrace.SamplingRate)
	}

	if config.CloudMonitoring != nil {
		if err := view.Register(defaultViews...); err != nil {
			return fmt.Errorf("failed to register observability views: %v", err)
		}
		view.SetReportingPeriod(defaultMetricsReportingInterval)
		view.RegisterExporter(exporter.(view.Exporter))
		logger.Infof("Start collecting and exporting metrics")
	}

	internal.AddGlobalServerOptions.(func(opt ...grpc.ServerOption))(opencensus.ServerOption(to))
	internal.AddGlobalDialOptions.(func(opt ...grpc.DialOption))(opencensus.DialOption(to))
	logger.Infof("Enabled OpenCensus StatsHandlers for clients and servers")

	return nil
}

// stopOpenCensus flushes the exporter's and cleans up globals across all
// packages if exporter was created.
func stopOpenCensus() {
	if exporter != nil {
		internal.ClearGlobalDialOptions()

View on GitHub (pinned to 03255a9237)

Solutions

  1. Call observability.Start() exactly once at process startup.
  2. Remove duplicate opencensus.RegisterViews/stats.Register calls for the gRPC default views.
  3. Move Start() to TestMain or a sync.Once guard so repeated invocations are no-ops.
  4. Call view.Unregister(defaultViews...) before re-registering if you must rebuild.

Example fix

// before
var startOnce sync.Once
// ...
func setup() {
    observability.Start(ctx) // called per request -> duplicate registration
}
// after
var startOnce sync.Once
func setup() {
    startOnce.Do(func() {
        if err := observability.Start(ctx); err != nil { log.Fatal(err) }
    })
}
Defensive patterns

Strategy: validation

Validate before calling

// Ensure Start() runs once per process.
var startOnce sync.Once
var startErr error
func EnsureObservability(ctx context.Context) {
    startOnce.Do(func() { startErr = observability.Start(ctx) })
}

Try / catch

if err := observability.Start(ctx); err != nil {
    if strings.Contains(err.Error(), "failed to register observability views") {
        // Duplicate registration: views already registered by another init; safe to continue.
        log.Printf("views already registered: %v", err)
    }
}

Prevention

When it happens

Trigger: Calling observability.Start() more than once in one process; importing both this observability package and a separate call to opencensus.RegisterViews/stats.Register that registers the same gRPC views; running the observability binary inside a test harness that already instrumented views.

Common situations: Mixing the gRPC Observability plugin with hand-rolled OpenCensus setup; init() in a helper package that also registers gRPC views; tests that run Start() per test case instead of once per process.

Related errors


AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07). Data as JSON: /api/errors/d48f4e710a54632b. Report an issue: GitHub.