libnyanpasu/clash-nyanpasu · warning
overlay document is not a mapping, skipped
Error message
overlay document is not a mapping, skipped
What it means
apply_overlay expects the overlay document to be a mapping (object) whose keys name config fields. If the parsed overlay value is not an object (list, scalar, null), the entire overlay is skipped with this warning rather than erroring, and the config is returned unmodified.
Source
Thrown at backend/nyanpasu-config/src/runtime/executor/overlay.rs:22
use std::sync::Arc;
use crate::runtime::value::ConfigValue;
use super::{
artifact::StepLogEntry,
ports::ScriptRunner,
value_util::{deep_merge_value, get_at, parse_dotted_path, remove_at, replace_at},
};
pub(super) fn apply_overlay(
overlay: &ConfigValue,
mut config: ConfigValue,
runner: &dyn ScriptRunner,
logs: &mut Vec<StepLogEntry>,
) -> ConfigValue {
let Some(entries) = overlay.as_object_arc() else {
logs.push(StepLogEntry::warn(
"overlay document is not a mapping, skipped",
));
return config;
};
// IndexMap iteration = document order (parity with Mapping iteration).
for (key, value) in entries.iter() {
// Legacy quirk kept verbatim (merge.rs:248): directive matching and
// the remainder path are lowercased; bare keys preserve case.
let lowered = key.to_ascii_lowercase();
if let Some(field) = strip_any(&lowered, &["prepend__", "prepend-"]) {
config = splice_sequence(config, field, value, true, logs);
} else if let Some(field) = strip_any(&lowered, &["append__", "append-"]) {
config = splice_sequence(config, field, value, false, logs);
} else if let Some(field) = lowered.strip_prefix("override__") {
config = override_path(config, field, value, logs);
} else if let Some(field) = lowered.strip_prefix("filter__") {
config = filter_path(config, field, value, runner, logs);View on GitHub (pinned to f7dbce2997)
Solutions
- Inspect the overlay document and wrap its content in a top-level mapping of field → operation
- Validate the overlay parses to an object before applying
- Re-export/re-save the overlay from the UI
- Confirm the correct file is wired as the overlay input
Example fix
# before (overlay.yaml)
- rules:
prepend: []
# after
rules:
prepend: [] Defensive patterns
Strategy: type-guard
Validate before calling
fn overlay_is_mapping(overlay: &ConfigValue) -> bool { overlay.as_object_arc().is_some() } Type guard
if !overlay_is_mapping(&overlay) { return Err(anyhow!("overlay must be a top-level mapping")); } Try / catch
let Some(entries) = overlay.as_object_arc() else {
return Err(anyhow!("overlay document is not a mapping"));
}; Prevention
- Ensure overlay files have a top-level YAML/JSON object, not a list or scalar
- Validate overlay serialization right after saving/exporting
- Confirm the correct file is registered as an overlay before apply
When it happens
Trigger: apply_with → apply_overlay: overlay.as_object_arc() returns None because the overlay file/value deserialized to a non-mapping ConfigValue.
Common situations: An overlay file whose top level is a YAML list or a bare scalar; a mis-serialized overlay (e.g. saved as `[...]` instead of `{...}`); selecting the wrong file as an overlay; an overlay that failed parsing and fell back to a non-object default.
Related errors
- merge value for `{field}` is not a sequence, skipped
- invalid remove entry, skipped
- unrecognized typed config migration state: existing {} is ne
- unsupported migration store schema version {}
- profiles.yaml failed validation: {errors:?}
AI-assisted analysis of libnyanpasu/clash-nyanpasu@f7dbce2997 (2026-09-08).
Data as JSON: /api/errors/dbc6639fe23aa859.
Report an issue: GitHub.