libnyanpasu/clash-nyanpasu · warning
runtime snapshot changed; refresh the inspection
Error message
runtime snapshot changed; refresh the inspection
What it means
This error is thrown by `RuntimeSnapshot::inspection_content` when the `snapshot_id` supplied by the caller does not match the id of the currently promoted runtime snapshot. Inspection data is a read-only projection of one immutable, promoted config-build snapshot; once the runtime config is rebuilt (e.g. after a profile switch or config patch), the old snapshot is replaced and any stale id is rejected. The mismatch check exists to prevent the UI from mixing node ids, diffs and logs from an inspection generation that no longer exists.
Source
Thrown at backend/tauri/src/client/runtime_inspection.rs:85
.any(|log| log.key == node.key && !log.entries.is_empty()),
tag: node.tag.clone(),
next: node.next.clone().unwrap_or_default(),
changed_fields: node
.snapshot
.changed_fields
.as_ref()
.map(|fields| fields.iter().cloned().collect()),
})
.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,View on GitHub (pinned to f7dbce2997)
Solutions
- Re-fetch the current inspection via `inspect_runtime()` to get the fresh snapshot_id and node list, then retry `inspect_runtime_node` with the new id.
- Wire the UI to invalidate/clear the inspection panel whenever the runtime config is patched or the core is restarted.
- Catch this error in the caller and treat it as a signal to refresh, not as a hard failure.
- Pass the snapshot_id straight from the latest `inspect_runtime()` response instead of caching it.
Example fix
// before
let content = client.inspect_runtime_node(&cached_snapshot_id, node_id).await?;
// after
let summary = client.inspect_runtime().await.ok_or_else(|| anyhow!("no runtime inspection"))?;
let content = client.inspect_runtime_node(&summary.snapshot_id, node_id)
.await
.or_else(|_| client.inspect_runtime_node(&summary.snapshot_id, node_id))?; Defensive patterns
Strategy: retry
Validate before calling
// call before inspect_runtime_node
let summary = client.inspect_runtime().await;
let fresh = summary.filter(|s| s.snapshot_id == cached_snapshot_id);
if fresh.is_none() { /* refresh summary first */ } Type guard
fn snapshot_is_current(summary: &RuntimeInspection, snapshot_id: &str) -> bool {
summary.snapshot_id == snapshot_id
} Try / catch
match client.inspect_runtime_node(&snapshot_id, node_id).await {
Ok(content) => content,
Err(e) if e.to_string().contains("snapshot changed") => {
let summary = client.inspect_runtime().await.ok_or_else(|| anyhow!("no inspection"))?;
client.inspect_runtime_node(&summary.snapshot_id, node_id).await?
}
Err(e) => return Err(e),
} Prevention
- Never cache snapshot_id across config changes; always read it from the latest inspect_runtime() call
- Invalidate inspection UI state on every config patch / profile change / core restart
- Treat the error message as a refresh signal, not a fatal failure
- Keep the summary and node requests in the same UI interaction cycle
When it happens
Trigger: Calling `NyanpasuClient::inspect_runtime_node(snapshot_id, node_id)` with a snapshot_id obtained from an earlier `inspect_runtime()` call, after the promoted runtime snapshot has been replaced (new config build, profile change, core restart). Even two snapshots with identical content from different lifetimes do not alias — the id check compares lifetime ids, not content.
Common situations: A frontend holds a stale snapshot id in UI state while a background config update promotes a new snapshot; a user edits a profile then the inspection panel lazily loads a node using the old id; long-lived UI sessions that never re-fetch the inspection summary after config changes.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- runtime snapshot node does not exist
- no promoted runtime snapshot; refresh the inspection
- proxy snapshot belongs to a retired instance
- provider snapshot belongs to a retired instance
- unimplemented!()
AI-assisted analysis of libnyanpasu/clash-nyanpasu@f7dbce2997 (2026-09-08).
Data as JSON: /api/errors/bf7f10eb3ef51c75.
Report an issue: GitHub.