OpenBMB/ChatDev · error · DesignError

Unsupported node type '{ntype}' for node '{nid}'. Only {allo

Error message

Unsupported node type '{ntype}' for node '{nid}'. Only {allowed} nodes are supported.

What it means

Raised by POST /api/tools/local when the sanitized filename fails the regex ^[A-Za-z0-9_-]+(\.py)?$. Only alphanumerics, underscores and hyphens are allowed, with an optional single .py suffix. Returns 400.

Source

Thrown at check/check.py:37

    """Raised when a workflow design cannot be loaded or validated."""



def _allowed_node_types() -> set[str]:
    names = set(iter_node_schemas().keys())
    if not names:
        raise DesignError("No node types registered; cannot validate workflow")
    return names


def _ensure_supported(graph: Dict[str, Any]) -> None:
    """Ensure the MVP constraints are satisfied for the provided graph."""
    for node in graph.get("nodes", []) or []:
        nid = node.get("id")
        ntype = node.get("type")
        allowed = _allowed_node_types()
        if ntype not in allowed:
            raise DesignError(
                f"Unsupported node type '{ntype}' for node '{nid}'. Only {allowed} nodes are supported."
            )
        if ntype == "agent":
            agent_cfg = node.get("config") or {}
            if not isinstance(agent_cfg, dict):
                raise DesignError(f"Agent node '{nid}' config must be an object")
            for legacy_key in ["memory"]:
                if legacy_key in agent_cfg:
                    raise DesignError(
                        f"'{legacy_key}' is deprecated. Use the new graph-level memory stores for node '{nid}'."
                    )


def load_config(
    config_path: Path,
    *,
    fn_module: Optional[str] = None,
    set_defaults: bool = True,

View on GitHub (pinned to 4fb2db0ea9)

Solutions

  1. Rename to letters/digits/underscore/hyphen only, e.g. "my_tool.py" or "my-tool".
  2. Strip or replace invalid characters client-side before submitting.
  3. Do not send directory paths; the endpoint writes into the function tools directory itself.

Example fix

# before
payload = {"filename": "my cool tool.v2.py", "content": code}
# after
import re
name = re.sub(r'[^A-Za-z0-9_-]', '_', 'my cool tool.v2'.split('.')[0])
payload = {"filename": name, "content": code}
Defensive patterns

Strategy: validation

Validate before calling

import re
if not re.match(r'^[A-Za-z0-9_-]+(\.py)?$', name.strip()):
    raise ValueError('invalid tool filename')

Type guard

const isValidToolName = (n: string) => /^[A-Za-z0-9_-]+(\.py)?$/.test(n.trim());

Prevention

When it happens

Trigger: Posting filenames containing spaces, dots other than a final .py, slashes, unicode characters, or multiple extensions such as "my tool.py", "a.b.py", "../evil", "tööl.py".

Common situations: Users pasting natural-language titles as filenames; attempts at path traversal (../); double extensions; non-ASCII tool names from internationalized UIs.

Related errors


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