Skip to content

navigate_path returns incorrect value when path traverses through a non-struct leaf node #311

@anaslimem

Description

@anaslimem

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:

{ "color": "red" }

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions