elkowar/eww · error

No root scope in graph

Error message

No root scope in graph

What it means

scope_graph.global_scope() indexes the graph at root_index and expects the scope to exist. If the root scope is missing, the scope graph was built or mutated incorrectly — again an internal invariant failure rather than something a config value directly controls.

Solutions

  1. Fix the config error that prevented the root scope from being created: run `eww logs` and validate the yuck file (`xmllint` on widget XML).
  2. Restart the daemon (`eww kill && eww daemon`) to rebuild the scope graph from scratch.
  3. Update eww — if the graph constructor can produce a missing root, it is a bug worth reporting upstream.
  4. Guard the accessor: return a Result or fall back to an empty scope instead of expecting.

Example fix

// before
pub fn global_scope(&self) -> &Scope {
    self.graph.scope_at(self.root_index).expect("No root scope in graph")
}
// after
pub fn global_scope(&self) -> Result<&Scope> {
    self.graph.scope_at(self.root_index).context("No root scope in graph")
}
Defensive patterns

Strategy: validation

Validate before calling

// verify the graph root exists before use
if graph.scope_at(graph.root_index).is_none() { return Err(anyhow!("scope graph has no root; config failed to parse")); }

Try / catch

match scope_graph.global_scope_checked() {
    Ok(root) => /* use root */,
    Err(e) => log::error!("scope graph unusable: {} — fix config and restart daemon", e),
}

Prevention

When it happens

Trigger: Calling global_scope() (directly or via currently_unused_globals) on a ScopeGraph whose root_index does not resolve, e.g. a graph constructed from an empty/failed parse where the root scope was never inserted or was removed.

Common situations: Seen during config parsing/reload when the widget hierarchy failed to build (malformed yuck XML) so the root scope never got created, or during teardown/rebuild races on hot reload.

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 elkowar/eww@48f5aa8b37 (2026-09-08). Data as JSON: /api/errors/7b93aef5a3d04faa. Report an issue: GitHub.

Appendix: source

Thrown at crates/eww/src/state/scope_graph.rs:136

    pub fn visualize(&self) -> String {
        self.graph.visualize()
    }

    pub fn currently_used_globals(&self) -> HashSet<VarName> {
        self.variables_used_in_self_or_subscopes_of(self.root_index)
    }

    pub fn currently_unused_globals(&self) -> HashSet<VarName> {
        let used_variables = self.currently_used_globals();
        self.global_scope().data.keys().cloned().collect::<HashSet<_>>().difference(&used_variables).cloned().collect()
    }

    pub fn scope_at(&self, index: ScopeIndex) -> Option<&Scope> {
        self.graph.scope_at(index)
    }

    pub fn global_scope(&self) -> &Scope {
        self.graph.scope_at(self.root_index).expect("No root scope in graph")
    }

    /// Evaluate a [SimplExpr] in a given scope. This will return `Err` if any referenced variables
    /// are not available in the scope. If evaluation fails for other reasons (bad types, etc)
    /// this will print a warning and return an empty string instead.
    pub fn evaluate_simplexpr_in_scope(&self, index: ScopeIndex, expr: &SimplExpr) -> Result<DynVal> {
        let needed_vars = self.lookup_variables_in_scope(index, &expr.collect_var_refs())?;
        // TODORW
        // TODO allowing it to fail here is painfully ugly
        match expr.eval(&needed_vars) {
            Ok(value) => Ok(value),
            Err(err) => {
                error_handling_ctx::print_error(anyhow!(err));
                Ok(DynVal::from(""))
            }
        }
    }

View on GitHub (pinned to 48f5aa8b37)