libnyanpasu/clash-nyanpasu · warning · StepLogEntry

filter expr failed, item removed: {error}

Error message

filter expr failed, item removed: {error}

What it means

This warning is logged by `apply_filter` when a Lua string predicate passed for a filter step fails to evaluate for an item (`runner.eval_item_predicate` returns Err). Following legacy parity semantics, a predicate evaluation error removes the item from the list rather than keeping it — the step succeeds overall, but the failed item is dropped and the error recorded in the step log.

Source

Thrown at backend/nyanpasu-config/src/runtime/executor/overlay.rs:167

fn apply_filter(
    items: Vec<ConfigValue>,
    filter: &ConfigValue,
    runner: &dyn ScriptRunner,
    logs: &mut Vec<StepLogEntry>,
) -> Vec<ConfigValue> {
    match filter {
        // Sequence of filters: composable multi-pass (merge.rs do_filter).
        ConfigValue::Array(filters) => filters
            .iter()
            .fold(items, |acc, sub| apply_filter(acc, sub, runner, logs)),
        // String: Lua boolean predicate; eval error removes the item (parity).
        ConfigValue::String(expr) => items
            .into_iter()
            .filter(|item| match runner.eval_item_predicate(expr, item) {
                Ok(keep) => keep,
                Err(error) => {
                    logs.push(StepLogEntry::warn(format!(
                        "filter expr failed, item removed: {error}"
                    )));
                    false
                }
            })
            .collect(),
        ConfigValue::Object(actions) => {
            let Some(ConfigValue::String(when)) = actions.get("when") else {
                logs.push(StepLogEntry::warn("invalid filter: missing `when`"));
                return items;
            };
            // Action selection mirrors the legacy match-arm order and typed
            // guards (merge.rs:122-231): an action whose guard fails falls
            // through to the next arm; when nothing matches, the `_` arm
            // warns once without evaluating `when` per item.
            enum FilterAction<'a> {
                Expr(&'a str),
                Override(&'a ConfigValue),

View on GitHub (pinned to f7dbce2997)

Solutions

  1. Read the logged `{error}` in the step log to see the exact Lua failure and fix the expression accordingly.
  2. Guard field access in the predicate (e.g. `return item.name ~= nil and item.name:find('x') ~= nil`) so missing fields don't error.
  3. Test the Lua expression against a representative item before shipping the enhance chain.
  4. If items should be kept on error rather than removed, restructure the filter to return a safe default (`true`) on missing data.

Example fix

// before: errors when 'region' is missing
filter: return item.region == 'HK'
// after: nil-safe predicate
filter: return item.region ~= nil and item.region == 'HK'
Defensive patterns

Strategy: validation

Validate before calling

-- nil-safe Lua predicate template
-- return type(item) == 'table' and item.region ~= nil and item.region == 'HK'

Try / catch

// inspect step log for filter failures
for entry in result.log.iter().filter(|e| e.level == Warn) {
    if entry.message.starts_with("filter expr failed") {
        eprintln!("filter error: {}", entry.message);
    }
}

Prevention

When it happens

Trigger: Using a `filter` step whose expression is a Lua string and the script raises a runtime error for an item — undefined variable/function in the expression, comparing incompatible types (e.g. number vs string), or accessing a missing item field without guarding.

Common situations: Filter expressions copied from examples referencing fields absent in the user's subscription items; Lua syntax/type errors after schema changes to item fields; hand-edited profile enhance scripts with typos.

Related errors


AI-assisted analysis of libnyanpasu/clash-nyanpasu@f7dbce2997 (2026-09-08). Data as JSON: /api/errors/c1c8f00ded352d52. Report an issue: GitHub.