astrid-runtime/astrid · error · GatewayError::Internal
unexpected response shape: {other:?}
Error message
unexpected response shape: {other:?} What it means
post_redeem treats an AdminResponseBody that is neither InviteRedeemed nor Error as a protocol violation and raises Internal with "unexpected response shape: {other:?}". It indicates the daemon replied successfully but with a variant the gateway didn't expect for an InviteRedeem request — usually a version skew between gateway and kernel.
Source
Thrown at crates/astrid-gateway/src/routes/auth.rs:142
// `InviteRedeem` doesn't need a verified caller principal — the
// token is the auth and the kernel's admin dispatcher bypasses
// the cap-gate for this variant. Stamp the IPC message with the
// `default` principal so the kernel's `resolve_caller` has *a*
// value to log; the handler ignores it.
let client = state.admin_client(PrincipalId::default())?;
let resp = client
.request(AdminRequestKind::InviteRedeem {
token: body.token,
public_key: body.public_key,
display_name: body.display_name,
})
.await
.map_err(|e| GatewayError::Internal(anyhow::anyhow!("daemon request: {e}")))?;
let redeemed = match resp {
AdminResponseBody::InviteRedeemed(r) => r,
AdminResponseBody::Error(msg) => return Err(GatewayError::Kernel(msg)),
other => {
return Err(GatewayError::Internal(anyhow::anyhow!(
"unexpected response shape: {other:?}"
)));
},
};
let session_token = mint_bearer(
&state.signing.signer,
&redeemed.principal,
state.config.session_lifetime_secs,
);
let session_expires_at_epoch = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.map_or(0, |d| d.as_secs())
.saturating_add(state.config.session_lifetime_secs);
Ok(Json(RedeemResponse {
principal: redeemed.principal,
group: redeemed.group,View on GitHub (pinned to affd8760f4)
Solutions
- Ensure gateway and kernel/daemon are built from compatible versions and redeploy together.
- Inspect the {other:?} payload to identify which variant came back and why.
- Add/extend a matching AdminResponseBody variant if the protocol intentionally gained a new response.
- Report/fix the daemon handler that answered InviteRedeem with the wrong response type.
Example fix
// before: version-skewed pair gateway v1.2 (expects InviteRedeemed) <-> kernel v1.3 (returns InviteRedeemedV2) // after: matching versions $ cargo build --workspace && redeploy gateway + kernel together
Defensive patterns
Strategy: try-catch
Validate before calling
// assert protocol compatibility at deploy time
gatewayVersion === kernelVersion || throw new Error('gateway/kernel version skew'); Type guard
fn is_redeem_response(resp: &AdminResponseBody) -> bool {
matches!(resp, AdminResponseBody::InviteRedeemed(_) | AdminResponseBody::Error(_))
} Try / catch
match resp {
AdminResponseBody::InviteRedeemed(r) => Ok(r),
AdminResponseBody::Error(msg) => Err(GatewayError::Kernel(msg)),
other => Err(GatewayError::Internal(anyhow!("unexpected response shape: {other:?}"))),
} // on this error: pin gateway+kernel to matching versions and redeploy Prevention
- Deploy gateway and kernel from the same workspace build/commit.
- Add a protocol-version handshake between gateway and daemon.
- Log the full {other:?} payload to speed up version-skew diagnosis.
- Add round-trip tests for each AdminRequestKind/Response pair.
When it happens
Trigger: POST /api/auth/redeem where the daemon's response deserializes to an AdminResponseBody variant other than InviteRedeemed or Error (e.g. PairToken, or a newer/older variant).
Common situations: Gateway and kernel built from mismatched versions so request/response enums drifted; a proxy or buggy daemon returning a wrong response type for the request.
Understand the failure class
Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.
Related errors
- daemon returned an unexpected status response: {other:?}
- shutdown stage daemon.shutdown_ack: unexpected response: {ot
- unexpected daemon response: {other:?}
- unexpected daemon response: {other:?}
- unexpected daemon response: {other:?}
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/e491f900ba043451.
Report an issue: GitHub.