In the Rust OpenFeature provider, the navigate_path function in provider.rs does not check whether the current path segment is the last one before returning a value. When a multi-segment path hits a non-struct value (like a string or number) at a non-terminal segment, the function returns that value as if the path was found instead of returning None.
The Go and Java providers both handle this correctly:
- Go returns
(nil, false) see TestGetValueForPath_NonMapValue in provider_test.go
- Java throws a
TypeMismatchError
Example
Given a flag value:
Resolving "my-flag.color.nonexistent" should fail, but instead it returns "red".
Root Cause
provider.rs lines 741–760:
fn navigate_path(value: Option<Struct>, path: &str) -> Option<Struct> {
let mut current = value?;
for part in path.split('.') {
let field = current.fields.get(part)?;
match &field.kind {
Some(value::Kind::StructValue(s)) => {
current = s.clone();
}
_ => {
// Comment says "if we're at the last part" but never checks
let mut fields = HashMap::new();
fields.insert(part.to_string(), field.clone());
return Some(Struct { fields });
}
}
}
Some(current)
}
The _ arm returns immediately without checking if the current segment is the last in the path.
Suggested Fix
Only return the wrapped value when the current segment is the final one. Otherwise, return None:
_ => {
if parts_remaining == 0 {
let mut fields = HashMap::new();
fields.insert(part.to_string(), field.clone());
return Some(Struct { fields });
} else {
return None; // Can't traverse further through a non-struct value
}
}
A test for this case should also be added, similar to Go's TestGetValueForPath_NonMapValue.
In the Rust OpenFeature provider, the
navigate_pathfunction inprovider.rsdoes not check whether the current path segment is the last one before returning a value. When a multi-segment path hits a non-struct value (like a string or number) at a non-terminal segment, the function returns that value as if the path was found instead of returningNone.The Go and Java providers both handle this correctly:
(nil, false)seeTestGetValueForPath_NonMapValueinprovider_test.goTypeMismatchErrorExample
Given a flag value:
{ "color": "red" }Resolving
"my-flag.color.nonexistent"should fail, but instead it returns"red".Root Cause
provider.rslines 741–760:The
_arm returns immediately without checking if the current segment is the last in the path.Suggested Fix
Only return the wrapped value when the current segment is the final one. Otherwise, return
None:A test for this case should also be added, similar to Go's
TestGetValueForPath_NonMapValue.