nushell/nushell · error

internal error: missing required scope frame

Error message

internal error: missing required scope frame

What it means

StateDelta maintains a stack of ScopeFrames; StateDelta::new() always pushes one frame and enter_scope/exit_scope push and pop it. last_scope_frame_mut() asserts the stack is non-empty before returning the top frame. A panic means the delta's scope stack was emptied — exit_scope was called more often than enter_scope, an engine-state bookkeeping bug rather than a script error.

Source

Thrown at crates/nu-protocol/src/engine/state_delta.rs:87

        self.vars.len()
    }

    pub fn num_decls(&self) -> usize {
        self.decls.len()
    }

    pub fn num_blocks(&self) -> usize {
        self.blocks.len()
    }

    pub fn num_modules(&self) -> usize {
        self.modules.len()
    }

    pub fn last_scope_frame_mut(&mut self) -> &mut ScopeFrame {
        self.scope
            .last_mut()
            .expect("internal error: missing required scope frame")
    }

    pub fn last_scope_frame(&self) -> &ScopeFrame {
        self.scope
            .last()
            .expect("internal error: missing required scope frame")
    }

    pub fn last_overlay_mut(&mut self) -> Option<&mut OverlayFrame> {
        let last_scope = self
            .scope
            .last_mut()
            .expect("internal error: missing required scope frame");

        if let Some(last_overlay_id) = last_scope.active_overlays.last() {
            Some(
                &mut last_scope
                    .overlays

View on GitHub (pinned to 8e03210652)

Solutions

  1. Audit custom code that calls working_set.enter_scope()/exit_scope() and make them strictly balanced (enter once, exit once per path)
  2. Use the standard parsing/evaluation entry points instead of driving scope frames directly
  3. Pin the last known-good nu-protocol/nu-parser pair and report the regression upstream with the script that triggers it

Example fix

// before: error path exits a scope it never entered
working_set.exit_scope();
if err { working_set.exit_scope(); return; }

// after: one enter pairs with one exit on every path
working_set.enter_scope();
let result = do_scoped(working_set);
working_set.exit_scope();
Defensive patterns

Strategy: validation

Validate before calling

// StateWorkingSet::delta is accessible in-crate; guard scope stack depth
// before engine operations if you drive scopes manually.
// (state.delta.scope starts with exactly one frame)
assert!(working_set.delta.scope.len() >= 1, "scope stack over-popped");

Prevention

When it happens

Trigger: An unbalanced enter_scope/exit_scope sequence (parser or engine code path that pops in both success and error branches), followed by any scope lookup: find_decl/find_overlay, variable resolution, merge into permanent state.

Common situations: Patched parsers or embedders driving StateWorkingSet scopes manually; regressions after upgrading nu-protocol/nu-parser; custom repl/eval loops that call exit_scope on error paths that never entered.

Related errors


AI-assisted analysis of nushell/nushell@8e03210652 (2026-08-17). Data as JSON: /api/errors/e719f2ac52a77e50. Report an issue: GitHub.