{"record":{"id":"9bd774cb940dd312","repo":"astrid-runtime/astrid","slug":"mcp-gateway-socket-path-has-no-parent","errorCode":null,"errorMessage":"MCP gateway socket path has no parent","messagePattern":"MCP gateway socket path has no parent","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-cli/src/commands/mcp/lifecycle.rs","lineNumber":379,"sourceCode":"        format!(\n            \"failed to create private runtime directory {}\",\n            path.display()\n        )\n    })?;\n    #[cfg(unix)]\n    {\n        use std::os::unix::fs::PermissionsExt;\n        std::fs::set_permissions(path, std::fs::Permissions::from_mode(0o700))?;\n    }\n    Ok(())\n}\n\n/// Bind-time cleanup and endpoint ownership check for a gateway listener.\npub(crate) async fn prepare_gateway_socket(_lifecycle: &GatewayLifecycleLock) -> Result<PathBuf> {\n    let path = gateway_socket_path()?;\n    let parent = path\n        .parent()\n        .ok_or_else(|| anyhow::anyhow!(\"MCP gateway socket path has no parent\"))?;\n    ensure_private_dir(parent)?;\n\n    if path.exists() {\n        if UnixStream::connect(&path).await.is_ok() {\n            anyhow::bail!(\"MCP gateway is already running at {}\", path.display());\n        }\n        // The lifecycle lock excludes every gateway generation. If the\n        // pathname survived a crash, this holder is now the only process that\n        // may remove and replace it.\n        std::fs::remove_file(&path).with_context(|| {\n            format!(\n                \"failed to remove stale MCP gateway socket {}\",\n                path.display()\n            )\n        })?;\n    }\n    Ok(path)\n}","sourceCodeStart":361,"sourceCodeEnd":397,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-cli/src/commands/mcp/lifecycle.rs#L361-L397","documentation":"`prepare_gateway_socket` resolves the gateway Unix socket path, ensures its parent directory exists with private permissions, and cleans up stale sockets. This error is thrown when the socket path has no parent directory — an invariant guard against a degenerate path (bare root), since the socket path always derives from the runtime home.","triggerScenarios":"The socket path (`mcp-gateway.sock`) resolves with no parent, i.e. runtime home configured to `/` or empty, or broken path construction.","commonSituations":"Runtime home misconfigured to the filesystem root; library bug in socket-path derivation. Not expected normally.","solutions":["Fix the runtime home / socket directory configuration.","Rerun with default configuration.","Report as a bug if stock settings trigger it."],"exampleFix":"// before\nASTRID_RUNTIME_HOME=/ astrid mcp gateway run\n// after\nASTRID_RUNTIME_HOME=$HOME/.local/share/astrid astrid mcp gateway run","handlingStrategy":"validation","validationCode":"let home = std::env::var(\"ASTRID_RUNTIME_HOME\").unwrap_or_default();\nassert!(home != \"/\" && !home.is_empty(), \"runtime home must be a normal directory\");","typeGuard":"fn has_parent(p: &std::path::Path) -> bool { p.parent().is_some() }","tryCatchPattern":"match prepare_gateway_socket(&lifecycle).await {\n    Err(e) if e.to_string().contains(\"has no parent\") => eprintln!(\"bad socket path configuration\"),\n    Err(e) => return Err(e),\n    Ok(path) => bind(path).await?,\n}","preventionTips":["Keep the socket inside a normal runtime home directory","Avoid filesystem-root path overrides","Validate socket path configuration at startup","Report occurrences with default config as bugs"],"tags":["mcp","lifecycle","socket","path"],"backgroundTag":"internal-invariant-violation","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}