xai-org/x-algorithm · error

LookupContext should not be decoded from Thrift

Error message

LookupContext should not be decoded from Thrift

What it means

VisibilityFilteringLookupContext is constructed programmatically from query fields and only ever serialized (to_thrift); decoding it back from Thrift is meaningless, so from_thrift panics as an explicit guard. The lookup context is request-side data, not a response type.

Source

Thrown at visibility-filtering-client/vf_client.rs:71

            _ => None,
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
#[serde(rename_all = "camelCase")]
pub struct VisibilityFilteringLookupContext {
    pub safety_level: SafetyLevel,
    pub for_user_id: u64,
}

impl MValCodec for VisibilityFilteringLookupContext {
    fn thrift_type() -> TType {
        TType::Struct
    }

    fn from_thrift(_proto: &mut dyn TInputProtocol) -> Self {
        panic!("LookupContext should not be decoded from Thrift")
    }

    fn to_thrift(&self, proto: &mut dyn TOutputProtocol) {
        let struct_id = TStructIdentifier::new("VisibilityFilteringLookupContext");
        proto.write_struct_begin(&struct_id).unwrap();
        proto
            .write_field_begin(&TFieldIdentifier::new("safety_level", TType::I32, 1))
            .unwrap();
        self.safety_level.to_thrift(proto);
        proto.write_field_end().unwrap();
        proto
            .write_field_begin(&TFieldIdentifier::new("for_user_id", TType::I64, 2))
            .unwrap();
        proto.write_i64(self.for_user_id as i64).unwrap();
        proto.write_field_end().unwrap();
        proto.write_field_stop().unwrap();
        proto.write_struct_end().unwrap();
    }

View on GitHub (pinned to 24c60942c5)

Solutions

  1. Remove the decode path; construct VisibilityFilteringLookupContext from its builder/query fields instead.
  2. If a round-trip is required for tests, skip decode-only/encode-only types via a marker or capability flag.
  3. Parse the underlying query fields directly rather than decoding the serialized context.

Example fix

// before
fn from_thrift(_proto: &mut dyn TInputProtocol) -> Self {
    panic!("LookupContext should not be decoded from Thrift")
}

// after: fail fast with a clear error instead of aborting the process
fn from_thrift(_proto: &mut dyn TInputProtocol) -> Self {
    unimplemented!("LookupContext must be built from query fields, not decoded")
}
// better: change the trait to split ReadCodec / WriteCodec so this arm cannot be reached
Defensive patterns

Strategy: type-guard

Type guard

trait ReadCodec { fn from_thrift(p: &mut dyn TInputProtocol) -> Self; }
fn decode<T: ReadCodec>(p: &mut dyn TInputProtocol) -> T { T::from_thrift(p) }
// VisibilityFilteringLookupContext does not implement ReadCodec -> decode is a compile error

Try / catch

if std::panic::catch_unwind(|| VisibilityFilteringLookupContext::from_thrift(proto)).is_err() { /* rebuild context from query fields instead */ }

Prevention

When it happens

Trigger: Calling MValCodec::from_thrift on VisibilityFilteringLookupContext — e.g. a generic Thrift reader, a round-trip test, or deserializing a captured request payload back into the context type.

Common situations: Codec conformance tests that round-trip every MValCodec type; generic decode utilities; attempts to reconstruct request context from logged Thrift bytes.

Related errors


AI-assisted analysis of xai-org/x-algorithm@24c60942c5 (2026-08-28). Data as JSON: /api/errors/efd794fad087356e. Report an issue: GitHub.