{"record":{"id":"024bfed1ab95cca3","repo":"OpenBMB/ChatDev","slug":"unsupported-node-type-ntype-for-node-nid","errorCode":null,"errorMessage":"Unsupported node type '{ntype}' for node '{nid}'. Only {allowed} nodes are supported.","messagePattern":"Unsupported node type '(.+?)' for node '(.+?)'\\. Only (.+?) nodes are supported\\.","errorType":"validation","errorClass":"DesignError","httpStatus":null,"severity":"error","filePath":"check/check.py","lineNumber":37,"sourceCode":"    \"\"\"Raised when a workflow design cannot be loaded or validated.\"\"\"\n\n\n\ndef _allowed_node_types() -> set[str]:\n    names = set(iter_node_schemas().keys())\n    if not names:\n        raise DesignError(\"No node types registered; cannot validate workflow\")\n    return names\n\n\ndef _ensure_supported(graph: Dict[str, Any]) -> None:\n    \"\"\"Ensure the MVP constraints are satisfied for the provided graph.\"\"\"\n    for node in graph.get(\"nodes\", []) or []:\n        nid = node.get(\"id\")\n        ntype = node.get(\"type\")\n        allowed = _allowed_node_types()\n        if ntype not in allowed:\n            raise DesignError(\n                f\"Unsupported node type '{ntype}' for node '{nid}'. Only {allowed} nodes are supported.\"\n            )\n        if ntype == \"agent\":\n            agent_cfg = node.get(\"config\") or {}\n            if not isinstance(agent_cfg, dict):\n                raise DesignError(f\"Agent node '{nid}' config must be an object\")\n            for legacy_key in [\"memory\"]:\n                if legacy_key in agent_cfg:\n                    raise DesignError(\n                        f\"'{legacy_key}' is deprecated. Use the new graph-level memory stores for node '{nid}'.\"\n                    )\n\n\ndef load_config(\n    config_path: Path,\n    *,\n    fn_module: Optional[str] = None,\n    set_defaults: bool = True,","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/OpenBMB/ChatDev/blob/4fb2db0ea90375ce1059f44fe03ffbd191a7a169/check/check.py#L19-L55","documentation":"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.","triggerScenarios":"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\".","commonSituations":"Users pasting natural-language titles as filenames; attempts at path traversal (../); double extensions; non-ASCII tool names from internationalized UIs.","solutions":["Rename to letters/digits/underscore/hyphen only, e.g. \"my_tool.py\" or \"my-tool\".","Strip or replace invalid characters client-side before submitting.","Do not send directory paths; the endpoint writes into the function tools directory itself."],"exampleFix":"# before\npayload = {\"filename\": \"my cool tool.v2.py\", \"content\": code}\n# after\nimport re\nname = re.sub(r'[^A-Za-z0-9_-]', '_', 'my cool tool.v2'.split('.')[0])\npayload = {\"filename\": name, \"content\": code}","handlingStrategy":"validation","validationCode":"import re\nif not re.match(r'^[A-Za-z0-9_-]+(\\.py)?$', name.strip()):\n    raise ValueError('invalid tool filename')","typeGuard":"const isValidToolName = (n: string) => /^[A-Za-z0-9_-]+(\\.py)?$/.test(n.trim());","tryCatchPattern":null,"preventionTips":["Sanitize names to [A-Za-z0-9_-] before submit","Never send paths or extensions other than .py"],"tags":["api","validation","filename","fastapi"],"backgroundTag":"invalid-filename-characters","analyzedSha":"4fb2db0ea90375ce1059f44fe03ffbd191a7a169","analyzedAt":"2026-08-27T14:35:29.622Z","schemaVersion":2},"datasetVersion":"2026-08-27T19:17:21.184Z"}