{"record":{"id":"bfafe0b3e6e856f7","repo":"OpenBMB/ChatDev","slug":"failed-to-save-workflow-file","errorCode":null,"errorMessage":"Failed to save workflow file","messagePattern":"Failed to save workflow file","errorType":"exception","errorClass":"WorkflowExecutionError","httpStatus":null,"severity":"error","filePath":"server/services/workflow_storage.py","lineNumber":99,"sourceCode":"    return safe_filename, yaml_content\n\n\ndef persist_workflow(\n    safe_filename: str,\n    content: str,\n    yaml_content: Any,\n    *,\n    action: str,\n    directory: Path,\n) -> None:\n    save_path = directory / safe_filename\n    logger = get_server_logger()\n\n    try:\n        save_path.write_text(content, encoding=\"utf-8\")\n    except Exception as exc:\n        logger.log_exception(exc, f\"Failed to save workflow file {safe_filename}\")\n        raise WorkflowExecutionError(\n            \"Failed to save workflow file\", details={\"filename\": safe_filename}\n        )\n\n    logger.info(\n        \"Workflow file persisted\",\n        log_type=LogType.WORKFLOW,\n        filename=safe_filename,\n        action=action,\n    )\n\n\ndef rename_workflow(source_filename: str, target_filename: str, *, directory: Path) -> None:\n    source_safe = validate_workflow_filename(source_filename, require_yaml_extension=True)\n    target_safe = validate_workflow_filename(target_filename, require_yaml_extension=True)\n\n    if source_safe == target_safe:\n        raise ValidationError(\"Source and target filenames must be different\", field=\"new_filename\")\n","sourceCodeStart":81,"sourceCodeEnd":117,"githubUrl":"https://github.com/OpenBMB/ChatDev/blob/4fb2db0ea90375ce1059f44fe03ffbd191a7a169/server/services/workflow_storage.py#L81-L117","documentation":"persist_workflow wraps save_path.write_text in a broad try/except and re-raises WorkflowExecutionError when writing the workflow file fails for any OS-level reason (permissions, disk full, missing parent directory). The original exception is logged via logger.log_exception first.","triggerScenarios":"Calling persist_workflow when the workflows directory is read-only, the disk is full, the parent directory was deleted between validation and save, or the process lacks write permissions.","commonSituations":"Running the server as a non-root user against a root-owned directory; container with a read-only volume mounted at the workflows path; disk quota exceeded in CI.","solutions":["Check the server log for the underlying exception logged by log_exception","Verify write permission on the target directory (chmod/chown) and that it exists","Free disk space or expand the volume","Ensure the directory is created (mkdir parents=True) before persisting"],"exampleFix":"# before\nsave_path.write_text(content, encoding=\"utf-8\")\n# after (defensive caller)\nworkflow_dir.mkdir(parents=True, exist_ok=True)\npersist_workflow(safe_filename, content, directory=workflow_dir)","handlingStrategy":"try-catch","validationCode":"workflow_dir.mkdir(parents=True, exist_ok=True)\nassert os.access(workflow_dir, os.W_OK), 'workflows dir not writable'","typeGuard":null,"tryCatchPattern":"try:\n    persist_workflow(name, content, directory=d)\nexcept WorkflowExecutionError as e:\n    logger.error('persist failed', e.details)\n    alert_ops_check_disk_and_perms()","preventionTips":["Health-check writable workflows dir at startup","Monitor disk usage alerts","Log details dict for ops triage"],"tags":["filesystem","permissions","io","workflow"],"backgroundTag":"file-write-permission-denied","analyzedSha":"4fb2db0ea90375ce1059f44fe03ffbd191a7a169","analyzedAt":"2026-08-27T14:35:29.622Z","schemaVersion":2},"datasetVersion":"2026-08-27T19:17:21.184Z"}