astrid-runtime/astrid · error

MCP gateway lock path has no parent

Error message

MCP gateway lock path has no parent

What it means

`open_lock_file` computes the parent directory of the lock-file path to create it with private (0600/0700) permissions. `Path::parent()` returns `None` only for paths with no directory component (e.g. a bare root). This error is an internal invariant guard: the gateway lock path is always derived from the runtime home, so hitting it means the path construction was corrupted.

Source

Thrown at crates/astrid-cli/src/commands/mcp/lifecycle.rs:99

#[derive(Debug)]
pub(crate) struct GatewaySupervisorLock(std::fs::File);

impl GatewayLifecycleLock {
    pub(crate) const fn file(&self) -> &std::fs::File {
        &self.0
    }
}

impl GatewaySupervisorLock {
    pub(crate) const fn file(&self) -> &std::fs::File {
        &self.0
    }
}

fn open_lock_file(path: &Path) -> Result<std::fs::File> {
    let parent = path
        .parent()
        .ok_or_else(|| anyhow::anyhow!("MCP gateway lock path has no parent"))?;
    ensure_private_dir(parent)?;
    let mut options = std::fs::OpenOptions::new();
    options.read(true).write(true).create(true).truncate(false);
    #[cfg(unix)]
    {
        use std::os::unix::fs::OpenOptionsExt as _;
        options.mode(0o600);
    }
    options
        .open(path)
        .with_context(|| format!("failed to open {}", path.display()))
}

fn try_lock_file(file: std::fs::File, path: &Path) -> Result<Option<std::fs::File>> {
    match file.try_lock() {
        Ok(()) => Ok(Some(file)),
        Err(std::fs::TryLockError::WouldBlock) => Ok(None),
        Err(std::fs::TryLockError::Error(error)) => {

View on GitHub (pinned to affd8760f4)

Solutions

  1. Check the runtime home / state directory configuration; it must be a normal directory path, not `/` or empty.
  2. Report as a bug if the path was constructed by the library itself with default configuration.
  3. Run with default settings (no home/path overrides) to confirm the error disappears.

Example fix

// before
ASTRID_RUNTIME_HOME=/ astrid mcp gateway run
// after
ASTRID_RUNTIME_HOME=$HOME/.local/share/astrid astrid mcp gateway run
Defensive patterns

Strategy: validation

Validate before calling

let home = std::env::var("ASTRID_RUNTIME_HOME").unwrap_or_default();
assert!(home != "/" && !home.is_empty(), "runtime home must be a normal directory");

Type guard

fn has_parent(p: &std::path::Path) -> bool { p.parent().is_some() }

Try / catch

if let Err(e) = open_lock_file(&path) {
    if e.to_string().contains("has no parent") {
        eprintln!("misconfigured lock path: {}", path.display());
    }
    return Err(e);
}

Prevention

When it happens

Trigger: Essentially only when the lock path is misconstructed to a bare filename or filesystem root, e.g. a runtime home directory configured to `/` or empty, causing `gateway lock path` to resolve without a parent directory.

Common situations: A misconfigured environment/runtime home pointing at `/`; a bug or unusual override producing a root-relative lock path. Practically unreachable with normal installation layouts.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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