Skip to content

fix: carry errorCode through provider error events - #2015

Open
yuchou87 wants to merge 1 commit into
open-feature:mainfrom
yuchou87:fix/eventdetails-errorcode
Open

fix: carry errorCode through provider error events#2015
yuchou87 wants to merge 1 commit into
open-feature:mainfrom
yuchou87:fix/eventdetails-errorcode

Conversation

@yuchou87

Copy link
Copy Markdown

What

Fixes #2014. A handler registered with OpenFeatureAPI.onProviderError always saw
details.getErrorCode() as null. Two places dropped it, and the PR fixes both.

1. The conversion to EventDetails did not copy it

EventDetails.fromProviderEventDetails(...) is the only path from a provider-emitted
ProviderEventDetails to the EventDetails handed to API-level handlers, and its builder
chain simply did not mention errorCode:

return builder()
        .domain(domain)
        .providerName(providerName)
        .flagsChanged(providerEventDetails.getFlagsChanged())
        .eventMetadata(providerEventDetails.getEventMetadata())
        .message(providerEventDetails.getMessage())
        .build();

It failed silently rather than loudly: EventDetails extends ProviderEventDetails, so
getErrorCode() compiles and returns null. And it could not be worked around from
application code — EventProvider.setEventProviderListener and EventProvider.attach are
both package-private, so there is no public way to observe a provider's events directly
and read the original ProviderEventDetails.

errorCode was the only field affected. ProviderEventDetails declares exactly four
fields — flagsChanged, message, eventMetadata, errorCode — and the other three were
already copied, so this is a missing line rather than a conversion that needs realigning.

2. OpenFeatureAPI.emitError never read the code it was holding

This one I found while preparing the fix for the first, and it is why the PR is two lines
rather than one. emitError raises PROVIDER_ERROR when a provider fails to initialise.
It takes an OpenFeatureError, which declares getErrorCode(), but built its event
details from the message alone:

ProviderEventDetails.builder().message(exception.getMessage()).build()

So even with the conversion fixed, a PROVIDER_ERROR the SDK raises itself still reached
handlers with no code — including for FatalError and ProviderNotReadyError, where the
code is precisely what a handler would act on. Spec 5.1.5 asks for it to be populated.

emitReady is left alone: it genuinely has no error code, so PROVIDER_READY events are
unchanged.

Why this is a fix: and not a breaking change

No consumer could have depended on null as a signal, because there was no way to obtain
a non-null value through this path. FeatureProviderStateManager.onEmit reads errorCode
off the original ProviderEventDetails rather than the converted EventDetails, so
provider state transitions are untouched.

Testing

  • EventsTest.shouldHaveAllProperties now asserts errorCode alongside the other fields.
    That is the existing test that should have caught this, and it exercises the
    user-visible path through a real handler rather than the package-private conversion.
  • EventsTest.errorsRaisedBySdkMustCarryErrorCode covers the second half: a provider that
    fails initialisation with FatalError, and a handler that must see PROVIDER_FATAL.
    It carries the @Specification annotation for 5.1.5, which nothing in the suite claimed
    before.
  • EventDetailsTest covers the conversion directly, including that an absent code stays
    null.

Both halves were verified to fail without their fix: reverting the EventDetails line
fails shouldHaveAllProperties and two of the three EventDetailsTest cases, and
reverting the emitError change fails errorsRaisedBySdkMustCarryErrorCode.

./mvnw test passes — 552 tests, 0 failures, 0 errors — and ./mvnw spotless:check is
clean, against main at 5bf9f56.

Note

Happy to split the emitError half into its own PR if you would rather keep the two
apart; I kept them together because they are the same defect reaching the user the same
way, and fixing only the conversion leaves onProviderError without a code for exactly
the failures that matter most.

A handler registered with OpenFeatureAPI.onProviderError always saw
getErrorCode() as null. Two places dropped it.

EventDetails.fromProviderEventDetails, the only path from a
provider-emitted ProviderEventDetails to the EventDetails handed to
API-level handlers, copied flagsChanged, eventMetadata and message but
not errorCode. It failed silently: EventDetails extends
ProviderEventDetails, so getErrorCode() compiles and returns null rather
than failing to compile, and there is no public way to observe a
provider's events directly to work around it.

OpenFeatureAPI.emitError, which raises PROVIDER_ERROR when a provider
fails to initialise, built its ProviderEventDetails from the exception's
message only, even though it holds an OpenFeatureError that exposes
getErrorCode(). Errors the SDK raises itself therefore reached handlers
with no code either, which is what spec 5.1.5 asks for.

errorCode was the only field missing from the conversion:
ProviderEventDetails declares four fields and the other three were
already copied. emitReady still sets no error code, so PROVIDER_READY
events are unchanged.

EventsTest.shouldHaveAllProperties now asserts errorCode alongside the
other fields, since that is the test that should have caught this.

Fixes open-feature#2014

Signed-off-by: Yu Chou <yuchou87@gmail.com>
@yuchou87
yuchou87 requested review from a team as code owners August 18, 2026 07:16
@coderabbitai

coderabbitai Bot commented Aug 18, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: d83e0c9a-947c-4c0d-8171-1b89aceb87b1

📥 Commits

Reviewing files that changed from the base of the PR and between 5bf9f56 and e4ee081.

📒 Files selected for processing (4)
  • src/main/java/dev/openfeature/sdk/EventDetails.java
  • src/main/java/dev/openfeature/sdk/OpenFeatureAPI.java
  • src/test/java/dev/openfeature/sdk/EventDetailsTest.java
  • src/test/java/dev/openfeature/sdk/EventsTest.java

Included review availability: Your plan includes up to 2 reviews per rolling hour; 1 remains after this review.


📝 Walkthrough

Walkthrough

Provider error codes now propagate through EventDetails and SDK-generated provider error events. Tests cover copied, unset, fatal, and general error codes across API and client handlers.

Changes

Provider error code propagation

Layer / File(s) Summary
Propagate and validate provider error codes
src/main/java/dev/openfeature/sdk/EventDetails.java, src/main/java/dev/openfeature/sdk/OpenFeatureAPI.java, src/test/java/dev/openfeature/sdk/*
EventDetails copies the provider error code. OpenFeatureAPI.emitError includes the exception error code in provider event details. Tests verify fatal, general, copied, unset, API-level, and client-level error codes.

Estimated code review effort: 2 (Simple) | ~10 minutes

Merge Risk: ⚪ Minimal · up to e4ee0

This localized change preserves provider error codes for error handlers and adds coverage for both affected paths; no actionable merge-blocking risk remains after normal checks and review.

Suggested reviewers: jarebudev

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the primary change: preserving errorCode in provider error events.
Description check ✅ Passed The description explains the defect, both fixes, test coverage, and validation results, and it is directly related to the changeset.
Linked Issues check ✅ Passed The PR copies provider errorCode through EventDetails and verifies API-level handlers receive it, satisfying issue #2014.
Out of Scope Changes check ✅ Passed All code and test changes support preserving errorCode in provider error events and validating the linked issue’s behavior.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@sonarqubecloud

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

EventDetails.fromProviderEventDetails drops errorCode, so API-level handlers never see it

1 participant