{"record":{"id":"1867baf720c48a7d","repo":"jdx/mise","slug":"dependent-resource-is-present","errorCode":null,"errorMessage":"dependent resource is present","messagePattern":"dependent resource is present","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/resources.rs","lineNumber":302,"sourceCode":"                outgoing\n                    .entry(dependency.clone())\n                    .or_default()\n                    .push(resource.id.clone());\n            }\n        }\n\n        let mut ready = incoming\n            .iter()\n            .filter_map(|(id, count)| (*count == 0).then_some(id.clone()))\n            .collect::<VecDeque<_>>();\n        let mut ordered = Vec::with_capacity(self.resources.len());\n        while let Some(id) = ready.pop_front() {\n            ordered.push(&self.resources[&id]);\n            if let Some(dependents) = outgoing.get(&id) {\n                for dependent in dependents {\n                    let count = incoming\n                        .get_mut(dependent)\n                        .expect(\"dependent resource is present\");\n                    *count -= 1;\n                    if *count == 0 {\n                        ready.push_back(dependent.clone());\n                    }\n                }\n            }\n        }\n\n        if ordered.len() != self.resources.len() {\n            let cycle = incoming\n                .into_iter()\n                .filter_map(|(id, count)| (count > 0).then_some(id.to_string()))\n                .collect::<Vec<_>>()\n                .join(\", \");\n            bail!(\"bootstrap resource dependency cycle: {cycle}\");\n        }\n        Ok(ordered)\n    }","sourceCodeStart":284,"sourceCodeEnd":320,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/system/resources.rs#L284-L320","documentation":"A Kahn topological-sort invariant panic in resource ordering: when decrementing a dependent's incoming-edge count, the code expects the dependent's entry to exist in the incoming-count map. The expect fires only if the graph maps are inconsistent — a dependent edge exists in `outgoing` but the corresponding node has no entry in `incoming`.","triggerScenarios":"Building a resource graph where a dependency edge is recorded (outgoing) but the dependent node's in-degree was never registered (missing from `incoming`) — e.g. resources referencing each other without being declared, or partial graph construction after deserialization changes.","commonSituations":"Config files declaring resource dependencies (`depends`) on resource IDs that are defined but were skipped during graph-node registration, or plugin-supplied resource graphs with dangling edges.","solutions":["Verify every ID appearing in outgoing edges also gets an incoming entry when the graph is built","Check that all declared resources are registered into the graph before sorting (no skipped/filtered nodes)","Add a graph-construction validation that fails with a clear message on dangling dependency references","If a dependency is optional, filter outgoing edges to known IDs when building `incoming`"],"exampleFix":"// before\nlet dependents = outgoing.get(&id);\n// after\nlet dependents = outgoing.get(&id).filter(|ds| ds.iter().all(|d| incoming.contains_key(d)));","handlingStrategy":"validation","validationCode":"for (id, deps) in &outgoing {\n    for d in deps {\n        assert!(incoming.contains_key(d), \"dangling dependency {d} -> not in incoming map\");\n    }\n}","typeGuard":"fn graph_consistent(g: &Graph) -> bool {\n    g.outgoing.values().flatten().all(|d| g.incoming.contains_key(d))\n}","tryCatchPattern":"let order = sorter.order().map_err(|e| anyhow!(\"resource graph invalid: {e}\"))?;","preventionTips":["Validate every declared dependency resolves to a registered resource at load time","Build incoming and outgoing maps in the same pass","Reject configs with dangling depends references early with clear messages"],"tags":["rust","panic","topological-sort","dependency-graph"],"backgroundTag":"internal-invariant-violation","analyzedSha":"533346cc374382b41ec5ff70536252b2e96e725c","analyzedAt":"2026-09-17T13:35:38.149Z","contentChangedAt":"2026-09-17T13:35:38.149Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}