open-feature / open-feature/java-sdk
EventDetails.fromProviderEventDetails drops errorCode, so API-level handlers never see it
- Vorherrschende Sprache
- Java
- Sterne
- 128
- Forks
- 61
- Ø Merge
- 5 Std. 57 Min.
- Gemergte PRs (30 T.)
- 26
Beschreibung
### Summary
`EventDetails.fromProviderEventDetails(...)` does not copy `errorCode`, so a handler
registered at API level — `OpenFeatureAPI.onProviderError(Consumer)` —
always sees `details.getErrorCode() == null`, even when the provider explicitly emitted
one.
`message`, `flagsChanged`, `providerName` and `eventMetadata` all arrive intact. Only
`errorCode` is lost, and it is lost silently: `EventDetails` extends
`ProviderEventDetails`, so `getErrorCode()` compiles and returns `null` rather than
failing to compile.
### Environment
- `dev.openfeature:sdk` **1.22.0**
### Steps to reproduce
Emit an error event carrying an explicit code from any `EventProvider` (here a probe
extending `InMemoryProvider`, which is already an `EventProvider`):
```java
probe.emitProviderError(ProviderEventDetails.builder()
.errorCode(ErrorCode.PROVIDER_NOT_READY)
.message("connect refused")
.build());
```
Log it from an API-level handler:
```java
OpenFeatureAPI.getInstance().onProviderError(details ->
log.error("event=PROVIDER_ERROR provider={} message={} error_code={}",
details.getProviderName(), details.getMessage(), details.getErrorCode()));
```
Observed:
```
event=PROVIDER_ERROR provider=InMemoryProvider message=connect refused error_code=null
```
`message` arrives, which rules out "the event never got delivered".
### Root cause
`EventDetails.fromProviderEventDetails(...)` is the only path from a provider-emitted
`ProviderEventDetails` to the `EventDetails` handed to API-level handlers, and its
builder chain simply does not mention `errorCode` (`EventDetails.java` on `main`):
```java
static EventDetails fromProviderEventDetails(
ProviderEventDetails providerEventDetails, String providerName, String domain) {
return builder()
.domain(domain)
.providerName(providerName)
.flagsChanged(providerEventDetails.getFlagsChanged())
.eventMetadata(providerEventDetails.getEventMetadata())
.message(providerEventDetails.getMessage())
.build();
}
```
`ProviderEventDetails` has four fields; three of them are copied. Decompiling 1.22.0
shows the same five-field builder chain, so the observed behaviour and the source agree,
and the two lines of evidence are independent of each other.
### Why it cannot be worked around
- API-level handlers receive `EventDetails`; the original `ProviderEventDetails` is not
reachable from there.
- There is no public way to observe a provider's events directly —
`EventProvider.setEventProviderListener` and `EventProvider.attach` are both
package-private.
- Recovering the code by parsing `message` is not viable: that text is entirely up to
each provider.
So until this is fixed, an application consuming provider events in Java has no error
code available at all.
### Note: the Go SDK does not drop it
`openfeature.EventDetails` in the Go SDK carries `ErrorCode` directly, so the
equivalent handler there does receive it. This is an SDK-level divergence between the
two implementations rather than a difference in how applications are written.
### Suggested fix
Add the missing line to the builder chain:
```java
.errorCode(providerEventDetails.getErrorCode())
```
One line, and I checked the two things that would have made it bigger than that.
**`errorCode` is the only field affected.** `ProviderEventDetails` declares exactly four
fields — `flagsChanged`, `message`, `eventMetadata`, `errorCode` — and the builder chain
transfers the first three. There is no second omission, so this is a missing line rather
than a conversion that needs realigning.
**Populating it does not make SDK-generated events ambiguous.** The events the SDK raises
itself build a `ProviderEventDetails` carrying no error code
(`OpenFeatureAPI.java:307` and `:320`), so their `getErrorCode()` stays `null` exactly as
it is today. The only thing that changes is that a code a provider explicitly set now
survives the conversion.
### Still present on `main`
Confirmed by reading the source at `5bf9f56`, not only the 1.22.0 bytecode:
`EventDetails.fromProviderEventDetails` still has no `.errorCode(...)` in its builder
chain, and all three call sites (`OpenFeatureAPI.java:531`, `:535`, `:543`) go through it.
Happy to open a PR.
Beitragsleitfaden
Rechercherichtung
Start in EventDetails.java at fromProviderEventDetails and check the three call sites in OpenFeatureAPI.java. Reproduce the provider error with InMemoryProvider and verify that an explicit ErrorCode reaches the API-level handler; done means the code is preserved while events without one still expose null.
Vom Indexierungsmodell aus dem Issue-Text verfasst.
Bewertung
- Tech-Stack
- java
- Bereich
- api
- Issue-Typ
- Bug
- Schwierigkeit
- 1/5
- Geschätzter Aufwand
- Unter einer Stunde
- Aktivitätsstatus
- Aktiv
- Klarheit
- Klar beschrieben
- Anfängerfreundlichkeit
- 88/100