open-feature / open-feature/go-sdk

[BUG] multiprovider: a failed Init leaves the event channel open forever and never shuts down providers that did initialize

Open
#561 0 comments 0 reactions 0 assignees View on GitHub
bug multi-provider Needs Triage
Dominant language
Go
Stars
249
Forks
61
Avg merge
2d 10h
Merged PRs (30d)
20

Description

## Observed behavior

When `InitWithContext` fails, it returns early — before `close(p.outboundEvents)` and before `shutdownFunc` is assigned:

https://github.com/open-feature/go-sdk/blob/6b0824c6c7b9b69e40f26aedcc4406ad4d3a5cec/openfeature/multi/multiprovider.go#L403-L430

`ShutdownWithContext` then short-circuits on `!p.initialized`, so there is no recovery path:

https://github.com/open-feature/go-sdk/blob/6b0824c6c7b9b69e40f26aedcc4406ad4d3a5cec/openfeature/multi/multiprovider.go#L569-L576

Observed:

```
Init error = Provider bad: context deadline exceeded ; Status() = "ERROR"
shutdownFunc nil after failed Init = true
consumer goroutine on EventChannel() blocks forever after failed Init
```

Two leaks follow. Any consumer ranging over `EventChannel()` blocks permanently, since the channel is never closed. And inner providers that *did* initialize successfully never receive `Shutdown`, so their connections and goroutines leak.

## Expected Behavior

A failed `InitWithContext` should leave the provider in a state where cleanup is possible:

- close `outboundEvents` (or make `ShutdownWithContext` handle the partially-initialized state rather than short-circuiting), and
- shut down the inner providers that did initialize, per [1.1.2.3](https://openfeature.dev/specification/sections/flag-evaluation#requirement-1123) and [§2.5](https://openfeature.dev/specification/sections/providers#25-shutdown).

## Steps to reproduce

```go
// one provider's InitWithContext returns an error; the other succeeds
mp, _ := multi.NewProvider(multi.StrategyFirstMatch,
multi.WithProvider("bad", &failingInitProvider{}),
multi.WithProvider("good", &okProvider{}))

err := mp.InitWithContext(ctx, of.EvaluationContext{}) // non-nil
go func() { for range mp.EventChannel() {} }() // never returns
mp.ShutdownWithContext(ctx) // no-ops; "good" never shut down
```

Contributor guide

Open the contributing guide

Research direction

Start in openfeature/multi/multiprovider.go at InitWithContext and ShutdownWithContext, then inspect EventChannel and the initialization path for partial success. Reproduce the failing-provider and successful-provider scenario from the issue. Done means a failed initialization permits cleanup, closes EventChannel, and shuts down providers that initialized successfully.

Written by the indexing model from the issue text.

Assessment

Tech stack
go
Domain
backend
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
78/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.