{"record":{"id":"0248038bd346b696","repo":"xai-org/x-algorithm","slug":"queryfields-should-not-be-decoded-from-thrift","errorCode":null,"errorMessage":"QueryFields should not be decoded from Thrift","messagePattern":"QueryFields should not be decoded from Thrift","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"visibility-filtering-client/vf_client.rs","lineNumber":98,"sourceCode":"        self.safety_level.to_thrift(proto);\n        proto.write_field_end().unwrap();\n        proto\n            .write_field_begin(&TFieldIdentifier::new(\"for_user_id\", TType::I64, 2))\n            .unwrap();\n        proto.write_i64(self.for_user_id as i64).unwrap();\n        proto.write_field_end().unwrap();\n        proto.write_field_stop().unwrap();\n        proto.write_struct_end().unwrap();\n    }\n}\n\nimpl MValCodec for SafetyLevel {\n    fn thrift_type() -> TType {\n        TType::I32\n    }\n\n    fn from_thrift(_proto: &mut dyn TInputProtocol) -> Self {\n        panic!(\"QueryFields should not be decoded from Thrift\")\n    }\n\n    fn to_thrift(&self, proto: &mut dyn TOutputProtocol) {\n        proto.write_i32(self.clone() as i32).unwrap();\n    }\n}\n\n#[async_trait]\npub trait VfClient {\n    async fn get_result(\n        &self,\n        post_ids: Vec<u64>,\n        safety_level: SafetyLevel,\n        for_user_id: u64,\n        context: Option<TwitterContextViewer>,\n    ) -> HashMap<u64, Result<Option<FilteredReason>>>;\n}\n","sourceCodeStart":80,"sourceCodeEnd":116,"githubUrl":"https://github.com/xai-org/x-algorithm/blob/24c60942c5c5fdad3a6addffb4c6e6d2f228f04f/visibility-filtering-client/vf_client.rs#L80-L116","documentation":"SafetyLevel is encoded as a Thrift i32 (write side only); from_thrift panics because the type was never meant to be read back from Thrift. The panic message mentions QueryFields, hinting this decode path was copied from a sibling encode-only type and is intentionally unreachable.","triggerScenarios":"Invoking MValCodec::from_thrift on SafetyLevel — generic decode utilities, round-trip codec tests, or reading captured Thrift bytes that contain the encoded i32.","commonSituations":"Symmetric codec test suites; refactors that decode previously write-only values; logging/replay tooling that deserializes emitted payloads.","solutions":["Do not decode SafetyLevel from Thrift; derive it from the response/query data that produced it.","If decoding is genuinely needed, implement from_thrift as proto.read_i32().unwrap().try_into() with proper error handling.","Split the codec trait into read-only/write-only capabilities so the compiler prevents this call."],"exampleFix":"// before\nfn from_thrift(_proto: &mut dyn TInputProtocol) -> Self {\n    panic!(\"QueryFields should not be decoded from Thrift\")\n}\n\n// after (if decoding becomes necessary)\nfn from_thrift(proto: &mut dyn TInputProtocol) -> Self {\n    let raw = proto.read_i32().unwrap();\n    SafetyLevel::try_from(raw).unwrap_or(SafetyLevel::default())\n}","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"trait ReadCodec { fn from_thrift(p: &mut dyn TInputProtocol) -> Self; }\n// SafetyLevel lacks ReadCodec; accidental decode fails to compile","tryCatchPattern":"if std::panic::catch_unwind(|| SafetyLevel::from_thrift(proto)).is_err() { /* recompute SafetyLevel from response metadata */ }","preventionTips":["Derive SafetyLevel from authoritative query/response data, not serialized bytes.","Use directional codec traits.","In replay tooling, parse the i32 explicitly instead of the codec."],"tags":["rust","thrift","deserialization","codec","visibility-filtering","encode-only"],"backgroundTag":"thrift-unimplemented-deserializer","analyzedSha":"24c60942c5c5fdad3a6addffb4c6e6d2f228f04f","analyzedAt":"2026-08-28T11:40:14.686Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}