{"record":{"id":"b5ed6e3607b43724","repo":"OpenBMB/ChatDev","slug":"no-node-types-registered-cannot-validate-workflow","errorCode":null,"errorMessage":"No node types registered; cannot validate workflow","messagePattern":"No node types registered; cannot validate workflow","errorType":"exception","errorClass":"DesignError","httpStatus":null,"severity":"error","filePath":"check/check.py","lineNumber":26,"sourceCode":"from check.check_workflow import check_workflow_structure\nfrom entity.config_loader import prepare_design_mapping\nfrom entity.configs import DesignConfig, ConfigError\nfrom schema_registry import iter_node_schemas\nfrom utils.io_utils import read_yaml\n\n\nensure_schema_registry_populated()\n\n\nclass DesignError(RuntimeError):\n    \"\"\"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\"]:","sourceCodeStart":8,"sourceCodeEnd":44,"githubUrl":"https://github.com/OpenBMB/ChatDev/blob/4fb2db0ea90375ce1059f44fe03ffbd191a7a169/check/check.py#L8-L44","documentation":"Raised by the POST /api/tools/local endpoint when the request body's filename field is empty or only whitespace after stripping. It is a 400 Bad Request from FastAPI's HTTPException, meaning the client omitted the required filename for creating a local function-calling tool file.","triggerScenarios":"POST /api/tools/local with {\"filename\": \"\"} or {\"filename\": \"   \"} (whitespace only) or omitting the field entirely if the Pydantic model defaults it to an empty string.","commonSituations":"Frontend forms submitting before the user typed a name; scripts that build the payload from an empty variable; JSON typos like \"file_name\" causing the default empty value to be used.","solutions":["Supply a non-empty filename in the JSON body, e.g. {\"filename\": \"my_tool\"}.","Trim client-side and disable the submit button until the name field is filled.","If the field is optional in your flow, generate a default name like f\"tool_{uuid4().hex[:8]}\"."],"exampleFix":"// before\nfetch('/api/tools/local', {method:'POST', body: JSON.stringify({filename: nameInput.value})})\n// after\nconst name = nameInput.value.trim();\nif (!name) throw new Error('filename required');\nfetch('/api/tools/local', {method:'POST', body: JSON.stringify({filename: name, content: code})})","handlingStrategy":"validation","validationCode":"const name = (req.body.filename ?? '').trim();\nif (!name) return res.status(400).send('filename required');","typeGuard":null,"tryCatchPattern":"catch (e) { if (e.status === 400 && e.detail === 'filename is required') { /* prompt user for name */ } }","preventionTips":["Require non-empty filename in the form before enabling submit","Trim input client-side"],"tags":["api","validation","fastapi","tools"],"backgroundTag":"required-field-missing","analyzedSha":"4fb2db0ea90375ce1059f44fe03ffbd191a7a169","analyzedAt":"2026-08-27T14:35:29.622Z","schemaVersion":2},"datasetVersion":"2026-08-27T19:17:21.184Z"}