{"record":{"id":"a40cb848133cb2d1","repo":"OpenBMB/ChatDev","slug":"expected-non-empty-string","errorCode":null,"errorMessage":"expected non-empty string","messagePattern":"expected non-empty string","errorType":"validation","errorClass":"ConfigError","httpStatus":null,"severity":"error","filePath":"entity/configs/base.py","lineNumber":229,"sourceCode":"        return dict(value)\n    if isinstance(value, Mapping):\n        return dict(value)\n    raise ConfigError(\"expected mapping\", path=str(value))\n\n\ndef require_mapping(data: Any, path: str) -> Mapping[str, Any]:\n    if not isinstance(data, Mapping):\n        raise ConfigError(\"expected mapping\", path)\n    return data\n\n\ndef require_str(data: Mapping[str, Any], key: str, path: str, *, allow_empty: bool = False) -> str:\n    value = data.get(key)\n    key_path = f\"{path}.{key}\" if path else key\n    if not isinstance(value, str):\n        raise ConfigError(\"expected string\", key_path)\n    if not allow_empty and not value.strip():\n        raise ConfigError(\"expected non-empty string\", key_path)\n    return value\n\n\ndef optional_str(data: Mapping[str, Any], key: str, path: str) -> str | None:\n    value = data.get(key)\n    if value is None or value == \"\":\n        return None\n    key_path = f\"{path}.{key}\" if path else key\n    if not isinstance(value, str):\n        raise ConfigError(\"expected string\", key_path)\n    return value\n\n\ndef require_bool(data: Mapping[str, Any], key: str, path: str) -> bool:\n    value = data.get(key)\n    key_path = f\"{path}.{key}\" if path else key\n    if not isinstance(value, bool):\n        raise ConfigError(\"expected boolean\", key_path)","sourceCodeStart":211,"sourceCodeEnd":247,"githubUrl":"https://github.com/OpenBMB/ChatDev/blob/4fb2db0ea90375ce1059f44fe03ffbd191a7a169/entity/configs/base.py#L211-L247","documentation":"ValidationError raised when require_yaml_extension is true (the default for most endpoints) and the filename does not end with .yaml or .yml.","triggerScenarios":"Calling get args/desc/raw/delete/rename/copy with 'myworkflow' or 'myworkflow.txt'; forgetting the extension when building the request.","commonSituations":"Clients treating the bare workflow name as the identifier; templates that append the wrong extension; API consumers assuming extension is implicit.","solutions":["Append .yaml or .yml to the filename in the request.","Centralize filename construction so the extension is always added once.","If listing names from another API, map name -> name + '.yaml' before file operations."],"exampleFix":"# before\nclient.get('/api/workflows/myflow/args')\n# after\nclient.get('/api/workflows/myflow.yaml/args')","handlingStrategy":"validation","validationCode":"if (!/\\.(yaml|yml)$/.test(name)) name += '.yaml';","typeGuard":"const hasYamlExt = (n: string) => /\\.(yaml|yml)$/.test(n);","tryCatchPattern":null,"preventionTips":["Centralize extension appending in one helper","Treat workflow id as 'name without extension' consistently"],"tags":["workflow","validation","file-extension"],"backgroundTag":"missing-file-extension","analyzedSha":"4fb2db0ea90375ce1059f44fe03ffbd191a7a169","analyzedAt":"2026-08-27T14:35:29.622Z","schemaVersion":2},"datasetVersion":"2026-08-27T19:17:21.184Z"}