OpenBMB/ChatDev · error · ConfigError

expected list of skill entries

Error message

expected list of skill entries

What it means

_coerce_allow_entries accepts None (empty list) or a list for the skills allow field; any other top-level type (string, mapping, int) raises ConfigError('expected list of skill entries') at the field path.

Source

Thrown at entity/configs/node/skills.py:161

    }

    @classmethod
    def from_dict(cls, data: Mapping[str, Any], *, path: str) -> "AgentSkillsConfig":
        mapping = require_mapping(data, path)
        enabled = optional_bool(mapping, "enabled", path, default=False)
        if enabled is None:
            enabled = False

        allow = cls._coerce_allow_entries(mapping.get("allow"), field_path=extend_path(path, "allow"))

        return cls(enabled=enabled, allow=allow, path=path)

    @staticmethod
    def _coerce_allow_entries(value: Any, *, field_path: str) -> List[str]:
        if value is None:
            return []
        if not isinstance(value, list):
            raise ConfigError("expected list of skill entries", field_path)

        result: List[str] = []
        for idx, item in enumerate(value):
            item_path = f"{field_path}[{idx}]"
            if isinstance(item, str):
                normalized = item.strip()
                if normalized:
                    result.append(normalized)
                continue
            if isinstance(item, Mapping):
                entry = AgentSkillSelectionConfig.from_dict(item, path=item_path)
                result.append(entry.name)
                continue
            raise ConfigError("expected skill entry mapping or string", item_path)
        return result

View on GitHub (pinned to 4fb2db0ea9)

Solutions

  1. Wrap the value in a list: allow: [my-skill]
  2. Remove the key entirely if no skills should be allowed (treated as [])
  3. Check JSON producers preserve arrays for single elements

Example fix

# before
allow: my-skill
# after
allow:
  - my-skill
Defensive patterns

Strategy: type-guard

Type guard

def is_valid_allow(v) -> bool:
    return v is None or isinstance(v, list)

Try / catch

try:
    SkillsConfig.from_dict(d, path='skills')
except ConfigError as e:
    if 'expected list of skill entries' in str(e):
        d['allow'] = [d['allow']] if not isinstance(d.get('allow'), list) else d['allow']
        SkillsConfig.from_dict(d, path='skills')

Prevention

When it happens

Trigger: Setting allow: my-skill (a single string) or allow: {name: my-skill} (a single mapping) instead of a list.

Common situations: Shorthand habits from other config systems that accept a single value; JSON tools collapsing one-element arrays; templating emitting a scalar.

Related errors


AI-assisted analysis of OpenBMB/ChatDev@4fb2db0ea9 (2026-08-27). Data as JSON: /api/errors/1f5f100d6eb072d3. Report an issue: GitHub.