libnyanpasu/clash-nyanpasu · error
runtime snapshot node does not exist
Error message
runtime snapshot node does not exist
What it means
Thrown by `RuntimeSnapshot::inspection_content` when `node_id` is out of bounds for the current snapshot's config graph (`graph.nodes.get(node_id as usize)` returned None). Node ids are indices into the snapshot graph built during the config pipeline; a valid id in one snapshot may be invalid in another. The library treats this as a caller contract violation rather than silently returning empty content.
Source
Thrown at backend/tauri/src/client/runtime_inspection.rs:94
.collect(),
}
}
fn inspection_content(
&self,
snapshot_id: &str,
node_id: u32,
) -> anyhow::Result<RuntimeInspectionContent> {
anyhow::ensure!(
self.inspection_id == snapshot_id,
"runtime snapshot changed; refresh the inspection"
);
let node = self
.inspection
.graph
.nodes
.get(node_id as usize)
.ok_or_else(|| anyhow::anyhow!("runtime snapshot node does not exist"))?;
let yaml = serde_yaml::to_string(&node.snapshot.config)?;
Ok(RuntimeInspectionContent {
diff: self
.inspection
.graph
.comparison_parent(node_id)
.map(|parent_id| -> anyhow::Result<_> {
Ok(RuntimeInspectionDiff {
parent_id,
hunks: self.inspection.graph.nodes[parent_id as usize]
.snapshot
.diff_yaml_to(&yaml)?,
})
})
.transpose()?,
yaml,
logs: self
.inspectionView on GitHub (pinned to f7dbce2997)
Solutions
- Always obtain node ids from the current `inspect_runtime()` summary's `nodes` array, never from cached data.
- Re-fetch the inspection summary whenever the snapshot changes, then map UI selections to fresh ids.
- Handle the error by reloading the whole inspection view (summary + node) instead of retrying the same id.
- Validate `node_id < summary.nodes.len()` client-side before calling.
Example fix
// before
client.inspect_runtime_node(&summary.snapshot_id, old_node_id).await?;
// after
if let Some(node) = summary.nodes.get(old_node_id as usize) {
client.inspect_runtime_node(&summary.snapshot_id, node.id).await?;
} else {
// refresh summary and re-resolve the node
} Defensive patterns
Strategy: validation
Validate before calling
if node_id as usize >= summary.nodes.len() {
anyhow::bail!("node {node_id} not in current inspection ({} nodes)", summary.nodes.len());
} Type guard
fn resolve_node<'a>(summary: &'a RuntimeInspection, node_id: u32) -> Option<&'a RuntimeInspectionNode> {
summary.nodes.get(node_id as usize)
} Try / catch
match client.inspect_runtime_node(&snapshot_id, node_id).await {
Ok(content) => content,
Err(e) if e.to_string().contains("node does not exist") => {
// reload summary and re-resolve the node id
let summary = client.inspect_runtime().await.ok_or_else(|| anyhow!("no inspection"))?;
client.inspect_runtime_node(&summary.snapshot_id, summary.root_id).await?
}
Err(e) => return Err(e),
} Prevention
- Source all node ids from the current summary's nodes array, never from persisted UI state
- Validate node_id against nodes.len() before calling
- Rebuild the inspection view whenever the snapshot generation changes
- Default to root_id when a previously selected node disappears
When it happens
Trigger: Calling `inspect_runtime_node` (via `NyanpasuClient`) with a node_id larger than or equal to `nodes.len()` of the promoted snapshot's graph — typically an id from a previous inspection summary, a hardcoded id, or an id from a different snapshot whose graph has fewer nodes.
Common situations: Frontend caches node ids from an old inspection tree; UI navigates to a node that no longer exists after the pipeline shape changed (profiles added/removed change the graph); off-by-one or index confusion between tree position and node id.
Related errors
- runtime snapshot changed; refresh the inspection
- no promoted runtime snapshot; refresh the inspection
- unimplemented!()
- IPC server is already initialized
- application actor call timed out
AI-assisted analysis of libnyanpasu/clash-nyanpasu@f7dbce2997 (2026-09-08).
Data as JSON: /api/errors/aac60bec07adb6fb.
Report an issue: GitHub.