astrid-runtime/astrid · error

helper returns the scoped reply

Error message

helper returns the scoped reply

What it means

This panic comes from `.expect("helper returns the scoped reply")` on the awaited result of the request-capsule helper in `request_capsule_round_trips_update_reply`. The helper waited `CAPSULE_TIMEOUT` for a reply on `TOPIC_UPDATE_RESPONSE_PREFIX.<correlation_id>` and returned Err — typically a timeout because no acceptable reply arrived on the scoped topic.

Source

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

            message: msg,
        });
    });

    let body = serde_json::json!({ "title": "renamed" });
    let payload = build_update_payload(correlation_id, "sess-1", &body).unwrap();
    let value = request_capsule(
        &bus,
        TOPIC_UPDATE_REQUEST,
        &response_topic,
        payload,
        correlation_id,
        &principal,
        None,
        &[test_provider_source_id()],
        CAPSULE_TIMEOUT,
    )
    .await
    .expect("helper returns the scoped reply");

    capsule.await.expect("stand-in capsule joins");
    let summary = parse_session_field(&value)
        .unwrap()
        .expect("present session");
    assert_eq!(summary.session_id, "sess-1");
    assert_eq!(summary.title.as_deref(), Some("renamed"));
}

/// A reply stamped for a different principal is ignored. This protects a
/// same-topic reply from satisfying another caller's request.
#[tokio::test]
async fn request_capsule_ignores_wrong_principal_reply() {
    let bus = Arc::new(EventBus::new());
    let principal = PrincipalId::new("alice").expect("valid principal");
    let correlation_id = "corr-want-principal";
    let response_topic = format!("{TOPIC_LIST_RESPONSE_PREFIX}.{correlation_id}");

View on GitHub (pinned to affd8760f4)

Solutions

  1. Verify the stand-in capsule publishes to `response_topic` (TOPIC_UPDATE_RESPONSE_PREFIX + correlation id) with a matching principal and the capsule's kernel source id.
  2. Increase CAPSULE_TIMEOUT or make it configurable for slow CI runners.
  3. Log the helper's error variant to distinguish timeout from filter-rejection.
  4. Ensure the request the capsule matched carried the same correlation_id the helper is listening for.

Example fix

// before
let value = update_session(...).await.expect("helper returns the scoped reply");
// after
let value = update_session(...).await
    .unwrap_or_else(|e| panic!("helper returns the scoped reply: {e:?}"));
Defensive patterns

Strategy: retry

Try / catch

let value = helper(...).await
    .unwrap_or_else(|e| panic!("helper returns the scoped reply: {e:?}"));

Prevention

When it happens

Trigger: The stand-in capsule never publishes the updated SUMMARY reply on the scoped response topic, publishes it with the wrong principal/source stamp so the helper filters it out, or the helper times out at CAPSULE_TIMEOUT before the reply lands.

Common situations: Reply published to the unscoped topic instead of the correlation-scoped one; response stamped with a different principal or source_id and rejected by the defensive checks; CAPSULE_TIMEOUT too short under CI load; topic prefix constants out of sync.

Understand the failure class

Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.

Related errors


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