grpc/grpc-go · error

no ObservabilityConfig found

Error message

no ObservabilityConfig found

What it means

Returned by observability.Start(ctx) when parseObservabilityConfig() succeeds but yields a nil config. The observability plugin is opt-in and expects configuration to be supplied (via the CLOUD_OBSERVABILITY_CONFIG env var or equivalent), so a parsed-but-nil result means the user invoked Start() without providing any observability config. It is a hard startup failure: nothing is instrumented.

Source

Thrown at gcp/observability/observability.go:54

// Start is the opt-in API for gRPC Observability plugin. This function should
// be invoked in the main function, and before creating any gRPC clients or
// servers, otherwise, they might not be instrumented. At high-level, this
// module does the following:
//
//   - it loads observability config from environment;
//   - it registers default exporters if not disabled by the config;
//   - it sets up telemetry collectors (binary logging sink or StatsHandlers).
//
// Note: this method should only be invoked once.
// Note: handle the error
func Start(ctx context.Context) error {
	config, err := parseObservabilityConfig()
	if err != nil {
		return err
	}
	if config == nil {
		return fmt.Errorf("no ObservabilityConfig found")
	}

	// Set the project ID if it isn't configured manually.
	if err = ensureProjectIDInObservabilityConfig(ctx, config); err != nil {
		return err
	}

	// Cleanup any created resources this function created in case this function
	// errors.
	defer func() {
		if err != nil {
			End()
		}
	}()

	// Enabling tracing and metrics via OpenCensus
	if err = startOpenCensus(config); err != nil {
		return fmt.Errorf("failed to instrument OpenCensus: %v", err)

View on GitHub (pinned to 03255a9237)

Solutions

  1. Set the CLOUD_OBSERVABILITY_CONFIG environment variable to a valid JSON config string before invoking Start().
  2. If you do not want observability, remove the observability.Start(ctx) call rather than letting it run unconfigured.
  3. Verify the config is exported in your container/process spec (Docker ENV, Kubernetes env, systemd Environment=).
  4. Log the parsed config at debug level to confirm the env var is actually read by the process.

Example fix

// before
func main() {
    _ = observability.Start(ctx) // returns "no ObservabilityConfig found"
}
// after
func main() {
    // CLOUD_OBSERVABILITY_CONFIG set in the environment:
    // {"cloud_logging":{},"cloud_trace":{"sampling_rate":1.0},"cloud_monitoring":{}}
    if err := observability.Start(ctx); err != nil {
        log.Fatalf("observability start failed: %v", err)
    }
    defer observability.End()
}
Defensive patterns

Strategy: validation

Validate before calling

// Fail fast before Start() if no config is present.
if os.Getenv("CLOUD_OBSERVABILITY_CONFIG") == "" {
    log.Println("observability disabled: CLOUD_OBSERVABILITY_CONFIG unset")
} else if err := observability.Start(ctx); err != nil {
    log.Fatalf("observability.Start: %v", err)
}

Try / catch

if err := observability.Start(ctx); err != nil {
    // observability is opt-in; treat a missing-config error as non-fatal and proceed without telemetry.
    log.Printf("observability not started: %v", err)
}

Prevention

When it happens

Trigger: Calling observability.Start(ctx) in main() without setting the CLOUD_OBSERVABILITY_CONFIG environment variable (or with it set to an empty/blank value). Also when the env var is present but maps to a config object that resolves to nil because no tracing, logging, or monitoring section was enabled.

Common situations: Copy-pasting a Start() call from a sample without shipping the config env var; running the same binary in a new environment (CI, fresh container) that lacks the exported variable; enabling observability behind a feature flag that is off.

Related errors


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