vectordotdev/vector · error

stack was empty during pop

Error message

stack was empty during pop

What it means

`pop_schema_scope` on `DisallowUnevaluatedPropertiesVisitor` pops its scope stack and asserts it was non-empty. The visitor maintains balanced push/pop pairs during scoped traversal; the panic fires when pop is called with nothing on the stack, indicating the traversal contract was broken.

Solutions

  1. Drive the visitor only through `visit_schema_object_scoped`/standard scoped traversal
  2. Audit any custom code that calls push/pop directly for balance
  3. Reproduce with a minimal schema to find the unbalanced traversal point
  4. Report upstream with the component config that reproduces it

Example fix

// before
visitor.pop_schema_scope(); // nothing pushed
// after
visitor.push_schema_scope("MyDef");
visitor.visit_schema_object_scoped(...);
visitor.pop_schema_scope();
Defensive patterns

Strategy: try-catch

Validate before calling

if visitor.is_scope_stack_empty() {
    return Err("pop_schema_scope called with empty scope stack".into());
}

Try / catch

if let Some(scope) = visitor.scope_stack.pop_if_nonempty() {
    // proceed
} else {
    tracing::error!("unbalanced pop_schema_scope detected");
}

Prevention

When it happens

Trigger: Calling `pop_schema_scope` without a prior `push_schema_scope` — invoking visitor methods directly instead of via the scoped traversal driver, or a schema structure causing unbalanced scope transitions.

Common situations: Custom traversal glue around scoped visitors; test code calling `pop_schema_scope` manually; nested `$ref` structures hitting an edge case in the driver.

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 vectordotdev/vector@bdb87aeaa4 (2026-09-16). Data as JSON: /api/errors/63985bcf00b86bfb. Report an issue: GitHub.

Appendix: source

Thrown at lib/vector-config/src/schema/visitors/unevaluated.rs:136

                unmark_or_flatten_schema(definitions, subschema);
            }
        }

        // If we encountered any subschema validation, or if this schema itself is an object schema,
        // mark the schema as closed by setting `unevaluatedProperties` to `false`.
        if had_relevant_subschemas || is_object_schema(schema) {
            mark_schema_closed(schema);
        }
    }
}

impl ScopedVisitor for DisallowUnevaluatedPropertiesVisitor {
    fn push_schema_scope<S: Into<SchemaReference>>(&mut self, scope: S) {
        self.scope_stack.push(scope.into());
    }

    fn pop_schema_scope(&mut self) {
        self.scope_stack.pop().expect("stack was empty during pop");
    }

    fn get_current_schema_scope(&self) -> &SchemaReference {
        self.scope_stack.current().unwrap_or(&SchemaReference::Root)
    }
}

fn unmark_or_flatten_schema(definitions: &mut Map<String, Schema>, schema: &mut SchemaObject) {
    // If the schema is an object schema, we'll unset `unevaluatedProperties` directly.
    // If it isn't an object schema, we'll see if the subschema is actually a schema
    // reference, and if so, we'll make sure to unset `unevaluatedProperties` on the
    // resolved schema reference itself.
    //
    // Like the top-level schema reference logic, this ensures the schema definition is
    // updated for subsequent resolution.
    if let Some(object) = schema.object.as_mut() {
        debug!("Unmarked object subschema directly.");

View on GitHub (pinned to bdb87aeaa4)