astrid-runtime/astrid · error
daemon did not return capsule metadata for WIT GC
Error message
daemon did not return capsule metadata for WIT GC
What it means
query_daemon_marks asks the kernel daemon via KernelRequest::GetCapsuleMetadata for capsule metadata used to collect WIT hashes for garbage collection. The kernel_api enum only treats the CapsuleMetadata variant as valid; any other KernelResponse variant means the daemon misunderstood or mishandled the request, so the code bails with this message.
Solutions
- Restart/upgrade the astrid daemon so its kernel_api matches the CLI's expectations and returns CapsuleMetadata
- Verify you are connecting to the correct workspace kernel socket (connect_kernel_for_workspace(None) resolution)
- Check the daemon logs for the handler of KernelRequest::GetCapsuleMetadata failing and returning an error variant
- Make the response handling tolerant by matching explicit error variants with clearer messages before the let-else
Example fix
// before
let astrid_core::kernel_api::KernelResponse::CapsuleMetadata(entries) = response else {
anyhow::bail!("daemon did not return capsule metadata for WIT GC")
};
// after
match response {
KernelResponse::CapsuleMetadata(entries) => Ok(entries),
other => anyhow::bail!("daemon returned {other:?} instead of capsule metadata for WIT GC"),
} Defensive patterns
Strategy: try-catch
Validate before calling
// after sending GetCapsuleMetadata, check variant before destructuring:
fn is_capsule_metadata(r: &KernelResponse) -> bool { matches!(r, KernelResponse::CapsuleMetadata(_)) } Type guard
fn as_capsule_metadata(r: KernelResponse) -> Option<Vec<CapsuleMetadataEntry>> { match r { KernelResponse::CapsuleMetadata(e) => Some(e), _ => None } } Try / catch
let marks = async { ... }.await.map_err(|e| {
eprintln!("WIT GC: daemon metadata query failed: {e}; skipping GC marks");
e
}); Prevention
- Keep daemon and CLI on matching kernel_api versions
- Log the unexpected response variant (Debug) to diagnose protocol drift
- Ping the daemon with a version/capability request before feature-specific calls
When it happens
Trigger: client.request(KernelRequest::GetCapsuleMetadata) resolves to a KernelResponse variant other than CapsuleMetadata (e.g. an error/ack variant), triggering the let-else bail at wit.rs:166 inside query_daemon_marks, called from collect_marks.
Common situations: Daemon running an older/other protocol version that responds with a legacy or error variant; connected to the wrong socket so a different kernel build answers; daemon-side handler for GetCapsuleMetadata not implemented and returns a generic fallback response; transient daemon restart returning an error envelope.
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
- Admin request timed out after
- an Astrid daemon appears to be running but its uplink is…
- an Astrid daemon appears to be running but its uplink is…
- an Astrid daemon is recorded as running (PID file) but its…
- anyhow::anyhow!(error)
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/4ee089a39766ea72.
Report an issue: GitHub.
Appendix: source
Thrown at crates/astrid-cli/src/commands/wit.rs:166
) -> anyhow::Result<HashSet<String>> {
let mut marks = query_daemon_marks()?;
let workspace_root = std::env::current_dir().ok();
marks.extend(collect_marks_in_workspace(
home,
workspace_root.as_deref(),
workspace_layout,
)?);
Ok(marks)
}
fn query_daemon_marks() -> anyhow::Result<HashSet<String>> {
let request = async {
let mut client = crate::socket_client::connect_kernel_for_workspace(None).await?;
let response = client
.request(astrid_core::kernel_api::KernelRequest::GetCapsuleMetadata)
.await?;
let astrid_core::kernel_api::KernelResponse::CapsuleMetadata(entries) = response else {
anyhow::bail!("daemon did not return capsule metadata for WIT GC")
};
Ok(entries
.into_iter()
.flat_map(|entry| entry.wit_hashes)
.collect())
};
if let Ok(handle) = tokio::runtime::Handle::try_current() {
tokio::task::block_in_place(|| handle.block_on(request))
} else {
let runtime = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.context("build runtime for daemon WIT metadata")?;
runtime.block_on(request)
}
}
fn collect_marks_in_workspace(View on GitHub (pinned to affd8760f4)