astrid-runtime/astrid · error · GatewayError::Internal
daemon request: {e}
Error message
daemon request: {e} What it means
issue_invite forwards the invite request to the daemon via the admin client; any transport or request failure is wrapped as an Internal error with context 'daemon request: {e}'. This indicates the gateway could not complete the round-trip to the daemon, as opposed to the daemon rejecting the invite itself (which becomes Forbidden).
Source
Thrown at crates/astrid-gateway/src/routes/invites.rs:93
.extensions()
.get::<CallerContext>()
.cloned()
.ok_or(GatewayError::Unauthorized)?;
let bytes = axum::body::to_bytes(req.into_body(), 64 * 1024)
.await
.map_err(|e| GatewayError::BadRequest(format!("body read: {e}")))?;
let body: IssueRequest = serde_json::from_slice(&bytes)?;
let client = state.admin_client_for(&caller)?;
let resp = client
.request(AdminRequestKind::InviteIssue {
group: body.group,
expires_secs: body.expires_secs,
max_uses: body.max_uses,
metadata: body.metadata,
})
.await
.map_err(|e| GatewayError::Internal(anyhow::anyhow!("daemon request: {e}")))?;
match resp {
AdminResponseBody::Invite(invite) => Ok(Json(IssueResponse { invite })),
AdminResponseBody::Error(msg) => Err(GatewayError::Forbidden { reason: msg }),
other => Err(GatewayError::Internal(anyhow::anyhow!(
"unexpected response shape: {other:?}"
))),
}
}
/// `OpenAPI` schema mirror of [`astrid_core::kernel_api::InviteSummary`].
/// Never constructed; resolves the `value_type` on
/// [`ListResponse::invites`] to a typed schema. Keep it
/// field-for-field with the serialized shape of `InviteSummary` —
/// note the field is `token_fingerprint` (not `fingerprint`), and
/// `issued_at_epoch` is always present.
#[derive(ToSchema)]
pub struct InviteSummaryView {
/// Domain-separated `blake3:<hex>` fingerprint of the token. Raw tokens are neverView on GitHub (pinned to affd8760f4)
Solutions
- Check that the daemon process is running and its socket/address matches the gateway's admin client config
- Inspect the wrapped source error (`e`) in logs to distinguish connection-refused vs timeout vs permission issues
- Retry the invite issuance after confirming daemon health
Example fix
// before
.map_err(|e| GatewayError::Internal(anyhow::anyhow!("daemon request: {e}")))?;
// after
.map_err(|e| {
tracing::error!(error = %e, "daemon request failed while issuing invite");
GatewayError::Internal(anyhow::anyhow!("daemon request: {e}"))
})?; Defensive patterns
Strategy: try-catch
Validate before calling
// Probe daemon reachability before issuing the invite
client.request(AdminRequestKind::Ping).await
.map_err(|_| anyhow::anyhow!("daemon unreachable"))?; Try / catch
match issue_invite(State(state), caller, Json(body)).await {
Ok(resp) => resp,
Err(GatewayError::Internal(e)) if e.to_string().starts_with("daemon request") => {
tracing::error!(%e, "daemon unreachable during invite issuance");
service_unavailable("daemon temporarily unavailable; retry")
}
Err(GatewayError::Forbidden { reason }) => forbidden(reason),
Err(e) => internal_error(e),
} Prevention
- Monitor daemon health (socket reachability) and alert before user requests fail
- Pin the daemon socket path in config and verify it after redeploys
- Implement a bounded retry for transient IPC failures on invite issuance
When it happens
Trigger: The client.request(AdminRequestKind::InviteIssue) future fails — daemon socket not reachable, connection dropped, timeout, or serialization failure while sending the invite issue request.
Common situations: Daemon process not running; wrong daemon socket/address in gateway config; daemon restarting during a request; permission denied on the unix socket.
Understand the failure class
Background: "API request failed": what wrapped HTTP errors from external APIs mean and how to find the real cause — this error's family across 29 libraries.
Related errors
- daemon closed guard uplink
- Failed to connect to daemon: {e}
- connection timed out after 5s
- daemon returned an unexpected status response
- daemon request: {e}
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/c66252ba5a28381b.
Report an issue: GitHub.