Skip to content

Commit bcf5a39

Browse files
fix: Include an error code in provider error events (#68)
**Requirements** - [x] I have added test coverage for new or changed functionality - [x] I have followed the repository's [pull request submission guidelines](../blob/main/CONTRIBUTING.md#submitting-pull-requests) - [ ] I have validated my changes against all supported platform versions **Related issues** OFP requirement 5.1.5 (sdk-specs `OFP-openfeature-provider-behavior`): `PROVIDER_ERROR` events SHOULD populate the event details' error code. **Describe the solution you've provided** When the LaunchDarkly data source transitions to `OFF`, the emitted `PROVIDER_ERROR` event details now include `ErrorCode.GENERAL` alongside the existing message: ```java emitProviderError(ProviderEventDetails.builder().message(message).errorCode(ErrorCode.GENERAL).build()); ``` Added `LifeCycleTest.itIncludesAnErrorCodeInErrorEvents`. **Describe alternatives you've considered** A more specific code (e.g. `PROVIDER_FATAL` for 401/403) was not used; OFP does not define a mapping, and the Python provider already uses `GENERAL` for the same transition. Choosing per-error codes would be a cross-SDK decision. **Additional context** OpenFeature Java SDK 1.23.0 fixed propagation of `errorCode` from provider event details to handler `EventDetails`, so handlers now observe this value. Link to Devin session: https://app.devin.ai/sessions/929f5530882d40bc95e55391e97536d5 Open in Devin Desktop: https://app.devin.ai/desktop/session/929f5530882d40bc95e55391e97536d5?variant=devin Requested by: @kinyoklion [SDK-3254](https://launchdarkly.atlassian.net/browse/SDK-3254) [SDK-3254]: https://launchdarkly.atlassian.net/browse/SDK-3254?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Overview** > Aligns **PROVIDER_ERROR** event details with OpenFeature provider behavior (OFP 5.1.5) by setting **`ErrorCode.GENERAL`** when the LaunchDarkly data source enters **`OFF`** and the provider moves to error state. Error messages are unchanged; handlers can now read **`detail.getErrorCode()`** (supported after OpenFeature Java SDK 1.23.0). > > Adds **`LifeCycleTest.itIncludesAnErrorCodeInErrorEvents`** to assert the error code on **`PROVIDER_ERROR`** using the existing delayed failing data source setup. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit dd3f67a. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
1 parent 2363198 commit bcf5a39

2 files changed

Lines changed: 21 additions & 1 deletion

File tree

‎src/main/java/com/launchdarkly/openfeature/serverprovider/Provider.java‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ private void handleDataSourceStatus(DataSourceStatusProvider.Status res, Complet
227227
var message = res.getLastError() != null
228228
? res.getLastError().toString()
229229
: "the provider has encountered a permanent error or has been shutdown";
230-
emitProviderError(ProviderEventDetails.builder().message(message).build());
230+
emitProviderError(ProviderEventDetails.builder().message(message).errorCode(ErrorCode.GENERAL).build());
231231
}
232232
}
233233
}

‎src/test/java/com/launchdarkly/openfeature/serverprovider/LifeCycleTest.java‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import com.launchdarkly.sdk.server.subsystems.ComponentConfigurer;
88
import com.launchdarkly.sdk.server.subsystems.DataSource;
99
import com.launchdarkly.sdk.server.subsystems.DataSourceUpdateSink;
10+
import dev.openfeature.sdk.ErrorCode;
1011
import dev.openfeature.sdk.ImmutableContext;
1112
import dev.openfeature.sdk.OpenFeatureAPI;
1213
import dev.openfeature.sdk.ProviderEvent;
@@ -357,6 +358,25 @@ public void itIncludesTheDataSourceErrorInErrorEvents() throws Exception {
357358
assertTrue(message.contains("bad"));
358359
}
359360

361+
@Test
362+
public void itIncludesAnErrorCodeInErrorEvents() throws Exception {
363+
var config = new LDConfig.Builder()
364+
.startWait(Duration.ZERO)
365+
.dataSource(new DelayedDataSourceFactory(Duration.ofMillis(100), false, true))
366+
.events(Components.noEvents())
367+
.build();
368+
var provider = new Provider("fake-key", config);
369+
CompletableFuture<ErrorCode> errorCode = new CompletableFuture<>();
370+
371+
OpenFeatureAPI.getInstance().on(ProviderEvent.PROVIDER_ERROR, (detail) -> {
372+
errorCode.complete(detail.getErrorCode());
373+
});
374+
375+
OpenFeatureAPI.getInstance().setProviderAndWait(provider);
376+
377+
assertEquals(ErrorCode.GENERAL, errorCode.get(1000, TimeUnit.MILLISECONDS));
378+
}
379+
360380
@Test
361381
public void itIncludesHttpDataSourceErrorInErrorEvents() throws Exception {
362382
var config = new LDConfig.Builder()

0 commit comments

Comments
 (0)