open-feature / open-feature/go-sdk

[BUG] a FATAL provider does not run newly registered PROVIDER_ERROR handlers immediately

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

Description

## Observed behavior

`emitOnRegistration` matches only three state/event pairs — READY/`ProviderReady`, ERROR/`ProviderError`, STALE/`ProviderStale`:

https://github.com/open-feature/go-sdk/blob/6b0824c6c7b9b69e40f26aedcc4406ad4d3a5cec/openfeature/event_executor.go#L154-L179

There is no `FatalState` branch, even though `stateFromEvent` can produce it:

https://github.com/open-feature/go-sdk/blob/6b0824c6c7b9b69e40f26aedcc4406ad4d3a5cec/openfeature/openfeature_api.go#L518-L535

So a handler attached while the provider is FATAL never fires:

```
state after fatal error event = "FATAL"
error handler fired immediately on registration while FATAL = false
```

## Expected Behavior

Per [5.3.3](https://openfeature.dev/specification/sections/events#requirement-533): *"Handlers attached after the provider is already in the associated state, **MUST** run immediately."* Combined with [1.7.5](https://openfeature.dev/specification/sections/flag-evaluation#requirement-175) (FATAL results from a `PROVIDER_ERROR` carrying `PROVIDER_FATAL`), a FATAL provider should fire `PROVIDER_ERROR` handlers on registration.

Two of the three siblings map FATAL → error for this purpose:

- **JS** — `[AllProviderStatus.FATAL]: AllProviderEvents.Error` in `event-utils.ts`.
- **Python** — `ProviderStatus.FATAL: ProviderEvent.PROVIDER_ERROR` in `_event_support.py`.

For fairness: **Java is also missing it** (`ProviderState.matchesEvent` omits FATAL), so Go isn't alone here — but the spec plus the JS/Python behaviour support the fix.

## Possibly worth folding in

While in this function: `emitOnRegistration` hardcodes `Message` (e.g. `"provider is in ready state"`) and drops `ErrorCode`, `FlagChanges` and `EventMetadata` from the event that actually caused the state.

The siblings also synthesize minimal details at this point, so this isn't a deviation on its own. But per [5.1.5](https://openfeature.dev/specification/sections/events#requirement-515) (`PROVIDER_ERROR` events SHOULD populate the error code), propagating at least `ErrorCode` would be an improvement — and fabricating a message where siblings leave the field unset is arguably worse than leaving it empty. Happy to split this out if preferred.

## Steps to reproduce

```go
// drive a provider to FATAL by emitting PROVIDER_ERROR with ErrorCode = of.ProviderFatalCode
fired := false
cb := func(d of.EventDetails) { fired = true }
api.AddHandler(of.ProviderError, &cb)

// client.State() == "FATAL", but fired == false
```

Contributor guide

Open the contributing guide

Research direction

Start in openfeature/event_executor.go at emitOnRegistration and compare its state/event mappings with stateFromEvent in openfeature/openfeature_api.go. Add coverage for registering a PROVIDER_ERROR handler after a PROVIDER_ERROR with PROVIDER_FATAL has moved the provider to FATAL, then run the relevant Go tests; done means the handler fires immediately.

Written by the indexing model from the issue text.

Assessment

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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.