[BUG] (ofrep) Error responses are parsed with snake_case keys, so no spec-conformant 400 can be parsed
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 85/100
Research direction
Start at lib/openfeature/ofrep/provider/client.rb in parse_error_response (around lines 101-119): change the required keys and parsed reads to camelCase (errorCode, errorDetails). Then update the stubbed error bodies in spec/openfeature/ofrep/provider/client_spec.rb and provider_spec.rb so the suite exercises the spec casing. Run those specs; done means a spec-conformant 400 returns the default value with the server's error code and message instead of raising ParseError, with any optional Provider#evaluate rescue work kept in scope only if agreed.
Written by the indexing model from the issue text.
Description
Description
OpenFeature::OFREP::Client#parse_error_response reads error response bodies using
snake_case keys (error_code, error_details), but OFREP specifies camelCase
(errorCode, errorDetails).
As a result the provider cannot parse a 400 from any spec-conformant OFREP server.
Because ParseError is not rescued by Provider#evaluate, and openfeature-sdk 0.3.1
(the pinned version) does not rescue provider exceptions either, the exception propagates
out of the application's flag-evaluation call.
Success parsing is unaffected and correct — this is only the error path.
The spec
evaluationFailure in service/openapi.yaml:
evaluationFailure:
type: object
properties:
key: { $ref: "#/components/schemas/key" }
errorCode: { type: string, enum: [PARSE_ERROR, TARGETING_KEY_MISSING, INVALID_CONTEXT, GENERAL] }
errorDetails: { $ref: "#/components/schemas/errorDetails" }
required: [key, errorCode]
bulkEvaluationFailure uses the same casing and requires errorCode.
The code
lib/openfeature/ofrep/provider/client.rb:101-119 (v0.1.2):
def parse_error_response(response)
required_keys = %w[key error_code] # spec: key, errorCode
parsed = JSON.parse(response.body)
missing_keys = required_keys - parsed.keys
unless missing_keys.empty?
raise OpenFeature::OFREP::ParseError.new(response)
end
OpenFeature::OFREP::Response.new(
...
error_code: error_code_mapper(parsed["error_code"]), # spec: errorCode
error_details: parsed["error_details"], # spec: errorDetails
...
)
end
For contrast, parse_success_response (line 121) is correct: %w[key value reason variant].
Steps to Reproduce
Point the provider at any spec-conformant OFREP server and trigger a 400 (for example by
sending a context the server rejects). The response body is the one from the spec's own
example, openapi.yaml lines 88-91:
{
"key": "my-flag",
"errorCode": "INVALID_CONTEXT",
"errorDetails": "Context property 'plan' must be a string"
}
The defect is in version-independent code, so it can be shown with the two constants
copied verbatim from client.rb:
require "json"
ERROR_REQUIRED = %w[key error_code] # client.rb:102
body = '{"key":"my-flag","errorCode":"INVALID_CONTEXT","errorDetails":"..."}'
ERROR_REQUIRED - JSON.parse(body).keys
# => ["error_code"] -> raise OpenFeature::OFREP::ParseError
Expected Behavior
Per OpenFeature spec requirement 1.4.10, evaluation does not raise. The caller receives the
default value, the server's error code (INVALID_CONTEXT here) and its errorDetails
message:
#<ResolutionDetails value=<default> error_code="INVALID_CONTEXT"
error_message="Context property 'plan' must be a string"
reason="ERROR">
Actual Behavior
OpenFeature::OFREP::ParseError is raised and reaches the caller:
parse_error_responseraisesParseError—error_codeis absent from the body.Provider#evaluate(provider.rb:84-87) rescues onlyUnauthorizedError,
InvalidOptionError,FlagNotFoundErrorandInternalServerError.ParseErroris
not in that list.openfeature-sdk0.3.1Client#fetch_*_valuehas no rescue at all (its onlyrescue
is inapi.rb:51, around client construction).
So client.fetch_boolean_value(...) raises instead of returning the default. The server's
real error code and message are lost in every case.
Note that on a newer openfeature-sdk, fetch_details rescues RECOVERABLE_ERRORS and
this would instead degrade to a misleading PARSE_ERROR with error_message="Parse error"
— better, but still the wrong code and still discarding the server's errorDetails. The
casing needs fixing either way.
Environment
- Ruby version: n/a — version-independent parsing logic (gem requires >= 3.4)
- Provider/Hook: ofrep (
openfeature-ofrep-provider) - Provider/Hook version: 0.1.2 (also present on
main) - OS: n/a
- openfeature-sdk version: 0.3.1 (the version the gemspec pins,
~> 0.3.1)
Additional Context
The existing tests encode the same casing, which is why this is green in CI. From
spec/openfeature/ofrep/provider/client_spec.rb, the stubbed server responses:
error_code: "TYPE_MISMATCH",
error_details: "expected type: boolean, got: string"
So a fix needs the fixtures corrected alongside the source, otherwise the suite fails for
the right reason and looks like a regression.
Suggested fix:
required_keys = %w[key errorCode], readingparsed["errorCode"]/parsed["errorDetails"].- Update the error-path fixtures in
client_spec.rbandprovider_spec.rbto camelCase. - Optionally add
ParseErrorandRateLimitedto the rescue list inProvider#evaluate,
so a malformed body from a server still returns a default rather than raising. (Happy to
split that into its own issue if you'd rather keep this one to the casing.)
I'm glad to open a PR for this.
- Dominant language
- Ruby
- Stars
- 5
- Forks
- 13
- Avg merge
- 15m
- Merged PRs (30d)
- 35
Getting set up
- No Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from open-feature/ruby-sdk-contrib
-
Difficulty 4/5 3-5 days Newbie friendliness 48/100
open-feature/ruby-sdk-contrib#268 ·
Maintainers usually reply within 1 day
-
Dependency DashboardOpen
Difficulty 4/5 3-5 days Newbie friendliness 20/100
open-feature/ruby-sdk-contrib#101 ·
Maintainers usually reply within 1 day
All issues in open-feature/ruby-sdk-contrib
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 85/100
heartcombo/simple_form#1874 ·
-
Category: OneSwap Status: Accepted
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
OpenNebula/one#8237 ·
-
enhancement
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
AllYourBot/hostedgpt#882 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 65/100
greenelab/lab-website-template#357 · 1 comment ·
-
Difficulty 1/5 Under an hour Newbie friendliness 85/100
shakacode/react_on_rails#5295 ·
Maintainers usually reply within 1 day