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
- Read the logged `{error}` in the step log to see the exact Lua failure and fix the expression accordingly.
- Guard field access in the predicate (e.g. `return item.name ~= nil and item.name:find('x') ~= nil`) so missing fields don't error.
- Test the Lua expression against a representative item before shipping the enhance chain.
- 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
- Guard every field access in Lua predicates with nil checks
- Test expressions against representative subscription items before shipping
- Prefer tolerant predicates (default to keeping the item) over strict comparisons
- Keep filter scripts in version control so regressions are traceable
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
- filter `when` failed, treated as false: {error}
- filter `expr` failed, item kept: {error}
- field `{field}` not found, skipped
- overlay document is not a mapping, skipped
- merge value for `{field}` is not a sequence, skipped
AI-assisted analysis of libnyanpasu/clash-nyanpasu@f7dbce2997 (2026-09-08).
Data as JSON: /api/errors/c1c8f00ded352d52.
Report an issue: GitHub.