astrid-runtime/astrid · error

reply deserializes

Error message

reply deserializes

What it means

In the gateway sessions test request_capsule_accepts_live_registry_source_id, the reply from the sessions route is parsed with parse_list_response and unwrapped via expect("reply deserializes"). A panic here means the HTTP response body no longer matches the JSON shape parse_list_response expects (sessions list schema changed or the handler returned an error body).

Source

Thrown at crates/astrid-gateway/src/routes/sessions_tests.rs:441

    });

    let payload = build_list_payload(correlation_id, None, DEFAULT_LIMIT, false);
    let value = request_capsule(
        &bus,
        TOPIC_LIST_REQUEST,
        &response_topic,
        payload,
        correlation_id,
        &principal,
        None,
        &[live_source],
        CAPSULE_TIMEOUT,
    )
    .await
    .expect("helper accepts the registry-provided source id");

    capsule.await.expect("stand-in capsule task joins");
    let parsed = parse_list_response(value).expect("reply deserializes");
    assert!(parsed.sessions.is_empty());
}

#[test]
fn resolve_search_limit_defaults_and_caps() {
    assert_eq!(resolve_search_limit(None).unwrap(), DEFAULT_SEARCH_LIMIT);
    assert_eq!(resolve_search_limit(Some(0)).unwrap(), DEFAULT_SEARCH_LIMIT);
    assert_eq!(resolve_search_limit(Some(50)).unwrap(), 50);
    assert_eq!(
        resolve_search_limit(Some(MAX_SEARCH_LIMIT)).unwrap(),
        MAX_SEARCH_LIMIT
    );
    assert!(matches!(
        resolve_search_limit(Some(MAX_SEARCH_LIMIT + 1)).unwrap_err(),
        GatewayError::BadRequest(_)
    ));
}

View on GitHub (pinned to affd8760f4)

Solutions

  1. Diff the route's actual response JSON against what parse_list_response expects and update the parser or handler
  2. Run the test with the response body printed/logged to see the mismatched shape
  3. Restore the wire-format field names/types required by the frozen schema
  4. Check that the registry-provided source id path actually succeeded (an earlier failure can yield an error body)

Example fix

// before
let parsed = parse_list_response(value).expect("reply deserializes");
// after
let parsed = parse_list_response(&value)
    .unwrap_or_else(|e| panic!("reply deserializes: {e}; body={value}"));
Defensive patterns

Strategy: try-catch

Validate before calling

// assert the shape before parsing in test helpers
assert!(value.get("sessions").map_or(false, |s| s.is_array()),
    "unexpected reply shape: {value}");

Type guard

fn is_list_reply(v: &serde_json::Value) -> bool {
    v.get("sessions").map_or(false, serde_json::Value::is_array)
}

Try / catch

let parsed = parse_list_response(&value)
    .unwrap_or_else(|e| panic!("reply deserializes: {e}; body={value}"));

Prevention

When it happens

Trigger: Running the test after changing the sessions list response serialization (renamed/removed fields, changed envelope), or when the route under test returns an error/empty body instead of the expected list JSON.

Common situations: Schema drift between the handler and the test's frozen parser; a regression in the route returning a JSON error object; serde field-type changes making deserialization fail.

Understand the failure class

Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.

Related errors


AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09). Data as JSON: /api/errors/75425ff5aba400a0. Report an issue: GitHub.