{"record":{"id":"0e3ea1d2446ed2b2","repo":"datawhalechina/hello-agents","slug":"e","errorCode":null,"errorMessage":"无法保存学习计划：{e}","messagePattern":"无法保存学习计划：(.+?)","errorType":"exception","errorClass":"FileWriteError","httpStatus":null,"severity":"error","filePath":"Co-creation-projects/Yixiang-Wu-LearningAgent/core/file_manager.py","lineNumber":60,"sourceCode":"            \"# 知识总结\\n\\n> 暂无知识笔记\\n\", encoding=\"utf-8\"\n        )\n        (domain_path / \"sessions\" / \"session_summary.md\").write_text(\n            \"# 学习历程\\n\\n> 暂无学习记录\\n\", encoding=\"utf-8\"\n        )\n\n    def save_plan(self, domain: str, plan_content: str) -> None:\n        \"\"\"\n        保存学习计划\n\n        Args:\n            domain: 领域名称\n            plan_content: 计划内容（markdown格式）\n        \"\"\"\n        plan_path = self.BASE_DIR / domain / \"plan.md\"\n        try:\n            plan_path.write_text(plan_content, encoding=\"utf-8\")\n        except Exception as e:\n            raise FileWriteError(f\"无法保存学习计划：{e}\")\n\n    def save_knowledge(self, domain: str, filename: str, content: str) -> None:\n        \"\"\"\n        保存知识笔记\n\n        Args:\n            domain: 领域名称\n            filename: 文件名\n            content: 文件内容\n        \"\"\"\n        knowledge_path = self.BASE_DIR / domain / \"knowledge\" / filename\n        try:\n            knowledge_path.write_text(content, encoding=\"utf-8\")\n        except Exception as e:\n            raise FileWriteError(f\"无法保存知识笔记：{e}\")\n\n    def save_session(self, domain: str, session_content: str) -> Path:\n        \"\"\"","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/datawhalechina/hello-agents/blob/606a07d341a47be773fab7f4b71177f53f96b2c3/Co-creation-projects/Yixiang-Wu-LearningAgent/core/file_manager.py#L42-L78","documentation":"FileWriteError raised by FileManager.save_plan when writing the learning plan markdown to BASE_DIR/<domain>/plan.md fails. The original exception (permission denied, missing parent directory, disk full, path is a directory) is interpolated into the message. Note the parent directory is never created by this method, so a domain directory that does not yet exist is the most common cause.","triggerScenarios":"Calling save_plan(domain, content) when BASE_DIR/<domain> does not exist (write_text does not create parent dirs); running the agent in a read-only container or with insufficient file permissions; BASE_DIR pointing to a path where <domain> collides with an existing file; disk-full or ENOSPC while writing; passing a domain containing path separators or invalid filename characters (e.g. '/', '\\0') so the OS rejects the path.","commonSituations":"First run of a new domain before any directory scaffold was created; deploying to Docker where BASE_DIR is a mounted volume with root ownership; CI runners with read-only workspace; domain string taken from LLM output containing '/' or newline characters.","solutions":["mkdir the parent before writing: plan_path.parent.mkdir(parents=True, exist_ok=True) inside save_plan","Sanitize the domain string (strip path separators and whitespace) before building the path","Check filesystem permissions/ownership of BASE_DIR and the mounted volume in deployment","Free up disk space or enlarge the volume if ENOSPC","Include type(e).__name__ and the path in the message so future failures are diagnosable"],"exampleFix":"# before\nplan_path = self.BASE_DIR / domain / \"plan.md\"\ntry:\n    plan_path.write_text(plan_content, encoding=\"utf-8\")\nexcept Exception as e:\n    raise FileWriteError(f\"无法保存学习计划：{e}\")\n\n# after\nplan_path = self.BASE_DIR / domain / \"plan.md\"\ntry:\n    plan_path.parent.mkdir(parents=True, exist_ok=True)\n    plan_path.write_text(plan_content, encoding=\"utf-8\")\nexcept OSError as e:\n    raise FileWriteError(f\"无法保存学习计划 {plan_path}: {type(e).__name__}: {e}\") from e","handlingStrategy":"validation","validationCode":"from pathlib import Path\n\ndef can_write_plan(base_dir: Path, domain: str) -> bool:\n    d = base_dir / domain\n    if d.exists() and not d.is_dir():\n        return False\n    if d.exists():\n        return os.access(d, os.W_OK)\n    return os.access(base_dir, os.W_OK)","typeGuard":null,"tryCatchPattern":"try:\n    fm.save_plan(domain, content)\nexcept FileWriteError as e:\n    logger.error(\"save_plan failed for %s: %s\", domain, e)\n    # surface to user; do not retry without fixing FS","preventionTips":["Have FileManager guarantee the domain directory tree exists (mkdir parents on every save)","Treat domain as a sanitized key: strip whitespace, reject '/' and reserved names before any path join","Run integration tests that save into a tmp_path fixture to catch permission/structure issues in CI"],"tags":["filesystem","io","python","pathlib","learning-agent"],"backgroundTag":null,"analyzedSha":"606a07d341a47be773fab7f4b71177f53f96b2c3","analyzedAt":"2026-08-14T22:57:27.446Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}