EpicGames/lore · error

response parse should work

Error message

response parse should work

What it means

A panic from `.expect("response parse should work")` on `QueryResponse::parse(collapse_bytes(&handle_output))` in `immutable_local_query_routes_to_local_store`. The handler completed but the returned bytes are not a valid QueryResponse — likely an empty body, an error-encoded response, or a serialization change in QueryResponse. The library throws this when the response bytes do not conform to the expected QueryResponse wire format.

Solutions

  1. Print `collapse_bytes(&handle_output)` (length + hex) before parsing to see what the handler actually produced.
  2. Check that the handler returned a QueryResponse and not an empty/error body (an early `return Ok(vec![])` path yields unparseable bytes).
  3. Verify QueryResponse::parse and its serialization counterpart are in sync after any format change.
  4. Ensure `collapse_bytes` concatenates all chunks including the header the parser expects.

Example fix

// before
let response = QueryResponse::parse(collapse_bytes(&handle_output))
    .expect("response parse should work");
// after
let raw = collapse_bytes(&handle_output);
let response = QueryResponse::parse(raw.clone())
    .unwrap_or_else(|e| panic!("response parse failed ({} bytes): {e:?}", raw.len()));
Defensive patterns

Strategy: validation

Validate before calling

let raw = collapse_bytes(&handle_output);
assert!(!raw.is_empty(), "handler returned empty body");
// optionally check a leading marker/version byte if QueryResponse has one

Type guard

fn is_parsable_query_response(raw: &[u8]) -> bool {
    QueryResponse::parse(raw.to_vec()).is_ok()
}

Try / catch

let response = QueryResponse::parse(raw).unwrap_or_else(|e| {
    panic!("QueryResponse parse failed ({:?}): {e:?}", &raw[..raw.len().min(32)])
});

Prevention

When it happens

Trigger: run_request_handler returned bytes that QueryResponse::parse rejects: an empty Vec (e.g. a ClientIdentify-style early return), an error frame instead of a query result, or a QueryResponse serialized with a different op/version than the parser expects.

Common situations: Changing QueryResponse's serialization (field order, count prefix) without updating parse; the handler returned an empty result because the query matched nothing (store routing wrong); collapsing multi-chunk responses incorrectly in the test helper `collapse_bytes`.

Related errors


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

Appendix: source

Thrown at lore-server/src/quic/replication_store_service/server.rs:1129

        // ImmutableLocalQuery should find the data via the local store
        let parse_output = service
            .parse_request_bytes(
                &CommandHeader::new(Command::ImmutableLocalQuery as QuicOpCode, 0, 0),
                collapse_bytes_without_header(&request.clone().to_quic_chunks()),
            )
            .expect("Failed to parse");
        assert!(matches!(
            parse_output,
            ParsedReplicationStoreRequest::Query(_)
        ));

        let handle_output = service
            .run_request_handler(AttributeMap::default().into(), parse_output)
            .await
            .expect("handler failed");
        let response = QueryResponse::parse(collapse_bytes(&handle_output))
            .expect("response parse should work");
        assert_eq!(response.results[0].match_made, StoreMatch::MatchFull);

        // ImmutableQuery should NOT find it (main store is empty)
        let parse_output = service
            .parse_request_bytes(
                &CommandHeader::new(Command::ImmutableQuery as QuicOpCode, 0, 0),
                collapse_bytes_without_header(&request.to_quic_chunks()),
            )
            .expect("Failed to parse");

        let handle_output = service
            .run_request_handler(AttributeMap::default().into(), parse_output)
            .await
            .expect("handler failed");
        let response = QueryResponse::parse(collapse_bytes(&handle_output))
            .expect("response parse should work");
        assert_eq!(response.results[0].match_made, StoreMatch::MatchNone);
    }

View on GitHub (pinned to 074eb0b0d1)