{"record":{"id":"50b52d8b1d262adf","repo":"EpicGames/lore","slug":"parsing-a-clientidentify-request-must-succeed","errorCode":null,"errorMessage":"parsing a ClientIdentify request must succeed","messagePattern":"parsing a ClientIdentify request must succeed","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"lore-server/src/quic/storage_service_v4.rs","lineNumber":547,"sourceCode":"            cmd,\n            ..CommandHeader::default()\n        }\n    }\n\n    #[tokio::test]\n    async fn parse_client_identify_opcode_returns_variant() {\n        use lore_transport::quic::storage_service::Command;\n        // The stores are unused by parse_request_bytes, so a minimal service suffices.\n        let (immutable_store, mutable_store, _exec) =\n            test_store_create().await.expect(\"Failed to create stores\");\n        let service = make_service(immutable_store, mutable_store);\n\n        let header = make_header(Command::ClientIdentify as u8);\n        let payload = Bytes::from(\"my-client/1.0\");\n\n        let parsed = service\n            .parse_request_bytes(&header, payload)\n            .expect(\"parsing a ClientIdentify request must succeed\");\n\n        assert!(\n            matches!(parsed, ParsedStorageRequestV4::ClientIdentify(_)),\n            \"expected ClientIdentify variant, got {parsed:?}\"\n        );\n    }\n\n    #[tokio::test]\n    async fn parse_client_identify_stores_value() {\n        use lore_transport::quic::storage_service::Command;\n        let (immutable_store, mutable_store, _exec) =\n            test_store_create().await.expect(\"Failed to create stores\");\n        let service = make_service(immutable_store, mutable_store);\n\n        let header = make_header(Command::ClientIdentify as u8);\n        let payload = Bytes::from(\"my-client/1.0\");\n\n        let parsed = service","sourceCodeStart":529,"sourceCodeEnd":565,"githubUrl":"https://github.com/EpicGames/lore/blob/074eb0b0d1194c997d7cf28b55519e3e197b3e23/lore-server/src/quic/storage_service_v4.rs#L529-L565","documentation":"A Rust test panic from `.expect(\"parsing a ClientIdentify request must succeed\")` on `StorageServiceV4::parse_request_bytes` in `parse_client_identify_opcode_returns_variant` (lore-server/src/quic/storage_service_v4.rs:547). A `ClientIdentify` command header with payload `my-client/1.0` was rejected by the parser, returning a `MessageParseError` instead of `ParsedStorageRequestV4::ClientIdentify(_)`. This indicates the V4 storage parser does not recognize or cannot decode the ClientIdentify opcode/payload as the test framed it.","triggerScenarios":"Calling `service.parse_request_bytes(&make_header(Command::ClientIdentify as u8), Bytes::from(\"my-client/1.0\"))` where the parser's match on the opcode lacks a ClientIdentify branch, `make_header` builds a header the parser rejects (version/opcode mismatch), or the payload fails ClientIdentify deserialization (e.g. the parser expects a length-prefixed or protobuf-encoded user-agent, not raw bytes).","commonSituations":"Seen when the ClientIdentify op was newly added to `Command` but `parse_request_bytes` at storage_service_v4.rs:134 wasn't updated, when the wire encoding of the user-agent changed, or when `Command::ClientIdentify as u8` collides with a different opcode after a protocol enum reorder.","solutions":["Print the MessageParseError: `.unwrap_or_else(|e| panic!(\"parse failed: {e:?}\"))` to see if it is unknown-opcode vs payload decode.","Add/verify the ClientIdentify branch in `parse_request_bytes` in lore-server/src/quic/storage_service_v4.rs so it maps `Command::ClientIdentify` to `ParsedStorageRequestV4::ClientIdentify`.","Confirm `Command::ClientIdentify`'s discriminant in lore_transport::quic::storage_service matches the opcode the parser dispatches on (no enum reordering drift).","Match the payload encoding the parser expects (e.g. wrap `my-client/1.0` in the expected length-prefixed/UTF-8 format) or update the parser to accept the documented format."],"exampleFix":"// before\nlet parsed = service\n    .parse_request_bytes(&header, payload)\n    .expect(\"parsing a ClientIdentify request must succeed\");\n// after\nlet parsed = service\n    .parse_request_bytes(&header, payload)\n    .unwrap_or_else(|e| panic!(\"parsing ClientIdentify failed: {e:?}\"));\n// and in parse_request_bytes:\n// Command::ClientIdentify => Ok(ParsedStorageRequestV4::ClientIdentify(\n//     ClientIdentify::decode(payload)?,\n// ))","handlingStrategy":"type-guard","validationCode":"// Ensure the opcode the test sends is one the parser dispatches on\nlet header = make_header(Command::ClientIdentify as u8);\nassert_ne!(header.opcode, 0, \"ClientIdentify discriminant must be non-zero and registered\");","typeGuard":"fn as_client_identify(p: &ParsedStorageRequestV4) -> Option<&ClientIdentify> {\n    match p {\n        ParsedStorageRequestV4::ClientIdentify(ci) => Some(ci),\n        _ => None,\n    }\n}","tryCatchPattern":"let parsed = service.parse_request_bytes(&header, payload)\n    .await\n    .unwrap_or_else(|e| panic!(\"ClientIdentify parse failed: {e:?}\"));\nassert!(matches!(parsed, ParsedStorageRequestV4::ClientIdentify(_)));","preventionTips":["Add a ClientIdentify branch to parse_request_bytes as soon as the Command variant is added.","Avoid reordering protocol enums; append new opcodes to keep discriminants stable.","Encode test payloads with the same serializer the parser decodes with."],"tags":["rust","test-panic","quic","request-parsing","protocol-v4"],"backgroundTag":"invalid-enum-value","analyzedSha":"074eb0b0d1194c997d7cf28b55519e3e197b3e23","analyzedAt":"2026-09-13T09:00:57.509Z","contentChangedAt":"2026-09-13T09:00:57.509Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}