A boolean flag satisfies a Float request in flagd-core: bool is a subclass of int
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 90/100
Research direction
Start in tools/openfeature-flagd-core/src/openfeature/contrib/tools/flagd/core/flagd_core.py, reading the float and integer type mappings, _check_type, and resolve_float_value. Add regression coverage for a boolean requested as Float and an integer requested as Float, then run the flagd-core tests. Done means the boolean returns the default with TYPE_MISMATCH while integer widening still returns 10.0.
Written by the indexing model from the issue text.
Description
Summary
A boolean flag satisfies a Float request. FlagdCore.resolve_float_value on a boolean flag returns 1.0 with reason STATIC and no error code, where the specification requires the code default and TYPE_MISMATCH.
The application sees a plausible value and no indication that anything went wrong — the worst failure mode a feature flag has.
The sibling case for the integer accessor is already guarded here, and the equivalent bug in the SDK's own type check was open-feature/python-sdk#619, fixed by open-feature/python-sdk#621. This is the same Python quirk in the remaining direction.
Reproducing
from openfeature.contrib.tools.flagd.core.flagd_core import FlagdCore
core = FlagdCore()
core.set_flags(
'{"flags":{"boolean-flag":{"state":"ENABLED",'
'"variants":{"on":true,"off":false},"defaultVariant":"on"}}}'
)
print(core.resolve_float_value("boolean-flag", 0.1))
# value=1.0 reason=STATIC error_code=None
# expected: value=0.1 reason=ERROR error_code=TYPE_MISMATCH
core.resolve_integer_value("boolean-flag", 1)
# raises TypeMismatchError -- the integer path is already guarded
Observed output:
FLOAT -> 1.0 | type float | reason STATIC | error_code None
INTEGER -> raised TypeMismatchError (the existing guard works)
Cause
Two things combine in tools/openfeature-flagd-core/src/openfeature/contrib/tools/flagd/core/flagd_core.py.
The float entry in the type map is wider than the integer one (lines 25-26):
"integer": ((int,), "int"),
"float": ((int, float), "float"),
and the bool guard in _check_type is conditioned on the integer type alone (line 223):
# For integer type, reject bool (since bool is subclass of int)
if flag_type == "integer" and isinstance(value, bool):
raise TypeMismatchError(...)
bool is a subclass of int, so isinstance(True, (int, float)) is True and a boolean passes the float check. resolve_float_value then widens it (lines 113-114):
result = self._resolve(flag_key, default_value, ctx, "float")
if isinstance(result.value, int):
result.value = float(result.value)
isinstance(True, int) is True, so float(True) gives 1.0.
The SDK cannot catch this one
Worth stating, because the fix for open-feature/python-sdk#619 might look as though it covers this. It does not, and it does not need to:
- For the integer accessor the SDK's map is a bare
int, soisinstance(True, int)passed and a boolean slipped through. That was #619, now fixed. - For the float accessor the SDK's map is a bare
float, andisinstance(True, float)isFalse— so the SDK rejects a boolean correctly on its own.
But by the time the value reaches the SDK it is a genuine float 1.0, because resolve_float_value already converted it. The evidence is destroyed upstream. Only this package can catch it.
Suggested fix
Widen the guard that is already there by one condition:
if flag_type in ("integer", "float") and isinstance(value, bool):
raise TypeMismatchError(
f"Expected type {type_name} but got {type(value).__name__}"
)
The comment above it ("since bool is subclass of int") applies verbatim to the float mapping, which is (int, float).
Two things worth a regression test either way: that boolean-flag requested as a Float is a mismatch, and that integer-flag requested as a Float still succeeds and still returns 10.0 rather than 10 — the widening on lines 113-114 is deliberate and must survive the fix.
How it surfaced
Running the Python implementation of the cross-language provider conformance suite (open-feature/spec#417) against a real flagd backend, in-process resolver. The suite runs an identical type-mismatch matrix against every provider in every language, and the row boolean-flag requested as Float passes in Go, Java and JavaScript and fails only in Python — because only Python has bool as a subclass of int.
It affects the in-process resolver only; RPC type-asserts correctly on the same row, which is what localises it to this package rather than to the flagd daemon or to the provider.
That is the second time this one Python quirk has been found by the suite, in two packages and two accessor directions — #619 was the first. A Java or Go suite could not have caught either.
- Dominant language
- Python
- Stars
- 27
- Forks
- 33
- Avg merge
- 11h 10m
- Merged PRs (30d)
- 14
Getting set up
- No Dockerfile or Docker Compose file
- No 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/python-sdk-contrib
-
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
open-feature/python-sdk-contrib#439 ·
Maintainers usually reply within 1 day
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
open-feature/python-sdk-contrib#433 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
open-feature/python-sdk-contrib#421 ·
Maintainers usually reply within 1 day
-
Difficulty 3/5 1-2 days Newbie friendliness 68/100
open-feature/python-sdk-contrib#446 ·
Maintainers usually reply within 1 day
-
Needs Triage question
Difficulty 4/5 3-5 days Newbie friendliness 48/100
open-feature/python-sdk-contrib#420 ·
Maintainers usually reply within 1 day
All issues in open-feature/python-sdk-contrib
Similar issues
-
adr
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
kristofdegrave/homeassistant-smart-charging#1607 ·
Maintainers usually reply within 1 day
-
namespace operations
Difficulty 2/5 1-3 hours Newbie friendliness 64/100
EclipseFdn/open-vsx.org#13665 ·
Maintainers usually reply within 1 day
-
doc good first issue help wanted
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
collective/icalendar#1865 · 2 comments ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
canonical/opentelemetry-collector-operator#409 ·
Maintainers usually reply within 1 day
-
Difficulty 1/5 Under an hour Newbie friendliness 85/100
mozilla/addons-release-tests#1243 ·
Maintainers usually reply within 1 day