EpicGames/lore · error

parsing a ClientIdentify request must succeed

Error message

parsing a ClientIdentify request must succeed

What it means

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.

Solutions

  1. Print the MessageParseError: `.unwrap_or_else(|e| panic!("parse failed: {e:?}"))` to see if it is unknown-opcode vs payload decode.
  2. 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`.
  3. Confirm `Command::ClientIdentify`'s discriminant in lore_transport::quic::storage_service matches the opcode the parser dispatches on (no enum reordering drift).
  4. 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.

Example fix

// before
let parsed = service
    .parse_request_bytes(&header, payload)
    .expect("parsing a ClientIdentify request must succeed");
// after
let parsed = service
    .parse_request_bytes(&header, payload)
    .unwrap_or_else(|e| panic!("parsing ClientIdentify failed: {e:?}"));
// and in parse_request_bytes:
// Command::ClientIdentify => Ok(ParsedStorageRequestV4::ClientIdentify(
//     ClientIdentify::decode(payload)?,
// ))
Defensive patterns

Strategy: type-guard

Validate before calling

// Ensure the opcode the test sends is one the parser dispatches on
let header = make_header(Command::ClientIdentify as u8);
assert_ne!(header.opcode, 0, "ClientIdentify discriminant must be non-zero and registered");

Type guard

fn as_client_identify(p: &ParsedStorageRequestV4) -> Option<&ClientIdentify> {
    match p {
        ParsedStorageRequestV4::ClientIdentify(ci) => Some(ci),
        _ => None,
    }
}

Try / catch

let parsed = service.parse_request_bytes(&header, payload)
    .await
    .unwrap_or_else(|e| panic!("ClientIdentify parse failed: {e:?}"));
assert!(matches!(parsed, ParsedStorageRequestV4::ClientIdentify(_)));

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


AI-assisted analysis of EpicGames/lore@074eb0b0d1 (2026-09-13). Data as JSON: /api/errors/50b52d8b1d262adf. Report an issue: GitHub.

Appendix: source

Thrown at lore-server/src/quic/storage_service_v4.rs:547

            cmd,
            ..CommandHeader::default()
        }
    }

    #[tokio::test]
    async fn parse_client_identify_opcode_returns_variant() {
        use lore_transport::quic::storage_service::Command;
        // The stores are unused by parse_request_bytes, so a minimal service suffices.
        let (immutable_store, mutable_store, _exec) =
            test_store_create().await.expect("Failed to create stores");
        let service = make_service(immutable_store, mutable_store);

        let header = make_header(Command::ClientIdentify as u8);
        let payload = Bytes::from("my-client/1.0");

        let parsed = service
            .parse_request_bytes(&header, payload)
            .expect("parsing a ClientIdentify request must succeed");

        assert!(
            matches!(parsed, ParsedStorageRequestV4::ClientIdentify(_)),
            "expected ClientIdentify variant, got {parsed:?}"
        );
    }

    #[tokio::test]
    async fn parse_client_identify_stores_value() {
        use lore_transport::quic::storage_service::Command;
        let (immutable_store, mutable_store, _exec) =
            test_store_create().await.expect("Failed to create stores");
        let service = make_service(immutable_store, mutable_store);

        let header = make_header(Command::ClientIdentify as u8);
        let payload = Bytes::from("my-client/1.0");

        let parsed = service

View on GitHub (pinned to 074eb0b0d1)