{"record":{"id":"f6a25ee4b0615fe8","repo":"libnyanpasu/clash-nyanpasu","slug":"remove-path-dotted-on-non-mapping-item-skippe","errorCode":null,"errorMessage":"remove path `{dotted}` on non-mapping item, skipped","messagePattern":"remove path `(.+?)` on non-mapping item, skipped","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"backend/nyanpasu-config/src/runtime/executor/overlay.rs","lineNumber":266,"sourceCode":"            logs.push(StepLogEntry::warn(\"invalid filter value, skipped\"));\n            items\n        }\n    }\n}\n\nfn remove_from_item(\n    item: ConfigValue,\n    paths: &Arc<[ConfigValue]>,\n    logs: &mut Vec<StepLogEntry>,\n) -> ConfigValue {\n    let mut current = item;\n    for path in paths.iter() {\n        match path {\n            ConfigValue::String(dotted) => {\n                // Legacy applies string paths to mapping items only\n                // (merge.rs:186 `key.is_string() && item.is_mapping()`).\n                if current.as_object_arc().is_none() {\n                    logs.push(StepLogEntry::warn(format!(\n                        \"remove path `{dotted}` on non-mapping item, skipped\"\n                    )));\n                    continue;\n                }\n                let segments = parse_dotted_path(dotted);\n                match remove_at(&current, &segments) {\n                    Some(next) => current = next,\n                    None => logs.push(StepLogEntry::warn(format!(\n                        \"remove path `{dotted}` not found, skipped\"\n                    ))),\n                }\n            }\n            ConfigValue::Number(index) => {\n                // Legacy numeric removal applies to sequence items only\n                // (merge.rs:221 `Value::Sequence(list) if key.is_i64()`).\n                if !matches!(current, ConfigValue::Array(_)) {\n                    logs.push(StepLogEntry::warn(\n                        \"remove index on non-sequence item, skipped\",","sourceCodeStart":248,"sourceCodeEnd":284,"githubUrl":"https://github.com/libnyanpasu/clash-nyanpasu/blob/f7dbce2997c633e484f54788035e770b3ee99773/backend/nyanpasu-config/src/runtime/executor/overlay.rs#L248-L284","documentation":"The `remove` action's string path entries only apply to mapping items; when the current item is not an object, the executor skips that path with a warning (legacy merge behavior applied only to mappings).","triggerScenarios":"A filter `remove: [\"some.path\"]` entry is evaluated against a sequence item that is an array or scalar.","commonSituations":"Mixed-type lists (rules as strings) being filtered with path-based removal; assuming remove works uniformly across item types.","solutions":["Scope the `when` predicate so only mapping items reach the remove action","Use a numeric index entry for sequence items instead of a dotted string path","Restructure the list so items to be removed from are mappings","Verify with logs which items are non-mapping and adjust the filter"],"exampleFix":"// before\nwhen: \"true\"\nremove: [\"udp\"]\n// after\nwhen: \"item.name != null\"\nremove: [\"udp\"]","handlingStrategy":"type-guard","validationCode":"// in `when`: only let mapping items reach string-path removals\n// when: \"item.name != null\"","typeGuard":"fn item_is_mapping(v: &ConfigValue) -> bool { v.as_object_arc().is_some() }","tryCatchPattern":null,"preventionTips":["Pair string remove paths with predicates that match only mappings","Use numeric entries for sequence-typed items","Run overlays with logging to spot skipped remove paths"],"tags":["config","filter","remove","type-mismatch"],"backgroundTag":"config-type-mismatch","analyzedSha":"f7dbce2997c633e484f54788035e770b3ee99773","analyzedAt":"2026-09-08T01:24:59.197Z","contentChangedAt":"2026-09-08T01:24:59.197Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}