astrid-runtime/astrid · error
native process storage mount broker unavailable
Error message
native process storage mount broker unavailable
What it means
Thrown when the native runtime builder cannot obtain the process storage mount broker: `self.process_storage_mount_broker.get().cloned()` returns `None`. The broker coordinates mounting process storage for capsules, and the native runtime treats it as mandatory, so assembly fails fast.
Solutions
- Initialize the process storage mount broker before starting the native runtime (the setter/OnceCell that populates `process_storage_mount_broker`)
- Ensure the standard kernel bootstrap sequence is used so the broker is installed in the right order
- If only launching capsules without process storage, use a runtime configuration that does not require the mount broker
Example fix
// before let kernel = AstridKernel::builder().build(); kernel.start_native_capsule_runtime().await?; // broker never set // after kernel.init_process_storage_mount_broker(broker)?; kernel.start_native_capsule_runtime().await?;
Defensive patterns
Strategy: validation
Validate before calling
if kernel.process_storage_mount_broker().is_none() {
return Err(anyhow!("process storage mount broker must be initialized first"));
} Type guard
fn has_mount_broker(kernel: &AstridKernel) -> bool {
kernel.process_storage_mount_broker().is_some()
} Prevention
- Initialize process storage before starting the capsule runtime in your bootstrap order
- Do not construct the kernel manually in tests; use the shared fixture that installs the broker
- Watch initialization order when refactoring async startup (OnceCell must be filled before use)
When it happens
Trigger: Starting the native capsule runtime when the OnceCell `process_storage_mount_broker` was never initialized (lib.rs:1955, `with_process_storage_mount_broker(...)`).
Common situations: Kernel constructed without process-storage initialization (e.g. storage layer skipped in embedded/test setups); race or ordering bug where the broker is set only after runtime start; code paths that construct the kernel manually instead of through the standard bootstrap that installs the broker.
Understand the failure class
Background: "X is required", "must be set", "cannot be empty": the missing-required-config error family, from Vertex AI project/location to WeChat keys — this error's family across 18 libraries.
Related errors
- native capsule runtime requires the authoritative principal…
- audit read failed
- authoritative principal store is unavailable
- canonical Astrid workspace requires the kernel workspace…
- describe WASM in system catalog
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/c88b95443e080227.
Report an issue: GitHub.
Appendix: source
Thrown at crates/astrid-kernel/src/lib.rs:1955
.with_astrid_workspace()
.with_principal_storage(
self.principal_store.clone().ok_or_else(|| {
anyhow::anyhow!(
"native capsule runtime requires the authoritative principal store"
)
})?,
self.principal_directory.clone(),
)
.with_workspace_branches(self.workspace_branches.clone().ok_or_else(|| {
anyhow::anyhow!(
"canonical Astrid workspace requires the kernel workspace branch service"
)
})?)
.with_process_storage_mount_broker(
self.process_storage_mount_broker
.get()
.cloned()
.ok_or_else(|| anyhow::anyhow!("native process storage mount broker unavailable"))?,
)
.with_registry(Arc::clone(&self.capsules))
.with_session_token(Arc::clone(&self.session_token))
.with_allowance_store(Arc::clone(&self.allowance_store))
.with_identity_store(Arc::clone(&self.identity_store))
.with_profile_cache(Arc::clone(&self.profile_cache))
.with_overlay_registry(Arc::clone(&self.overlay_registry))
// Thread the live group config so capsule invocation checks observe
// runtime group mutations without requiring capsule reloads. Load-time
// run-loop decisions take their own explicit snapshot.
.with_live_group_config(Arc::clone(&self.groups))
// Hand this capsule its operator-approved local-egress allowlist (if
// any) so the SSRF airlock can exempt sanctioned loopback/private
// endpoints for it. Absent entry = empty = no exemptions.
.with_local_egress(
self.local_egress
.read()
.unwrap_or_else(std::sync::PoisonError::into_inner)View on GitHub (pinned to affd8760f4)