datawhalechina/hello-agents · error · FileWriteError

无法保存知识笔记:{e}

Error message

无法保存知识笔记:{e}

What it means

FileWriteError raised by FileManager.save_knowledge when writing a knowledge note to BASE_DIR/<domain>/knowledge/<filename> fails. write_text does not create intermediate directories, so a missing knowledge/ subdirectory is the dominant trigger. The bare except Exception also swallows the traceback unless re-raised with `from e`.

Source

Thrown at Co-creation-projects/Yixiang-Wu-LearningAgent/core/file_manager.py:75

        try:
            plan_path.write_text(plan_content, encoding="utf-8")
        except Exception as e:
            raise FileWriteError(f"无法保存学习计划:{e}")

    def save_knowledge(self, domain: str, filename: str, content: str) -> None:
        """
        保存知识笔记

        Args:
            domain: 领域名称
            filename: 文件名
            content: 文件内容
        """
        knowledge_path = self.BASE_DIR / domain / "knowledge" / filename
        try:
            knowledge_path.write_text(content, encoding="utf-8")
        except Exception as e:
            raise FileWriteError(f"无法保存知识笔记:{e}")

    def save_session(self, domain: str, session_content: str) -> Path:
        """
        保存单次学习会话记录

        Args:
            domain: 领域名称
            session_content: 会话内容

        Returns:
            保存的文件路径
        """
        date = datetime.now().strftime("%Y-%m-%d")
        time = datetime.now().strftime("%H-%M")
        session_path = self.BASE_DIR / domain / "sessions" / f"session_{date}_{time}.md"

        try:
            session_path.write_text(session_content, encoding="utf-8")

View on GitHub (pinned to 606a07d341)

Solutions

  1. mkdir the knowledge dir first: knowledge_path.parent.mkdir(parents=True, exist_ok=True)
  2. Validate filename: reject empty strings, '/' and '..' components to prevent path traversal
  3. Fix directory permissions/ownership on BASE_DIR and descendants
  4. Chain the original exception with `raise ... from e` to preserve the traceback

Example fix

# before
knowledge_path = self.BASE_DIR / domain / "knowledge" / filename
try:
    knowledge_path.write_text(content, encoding="utf-8")
except Exception as e:
    raise FileWriteError(f"无法保存知识笔记:{e}")

# after
if not filename or '/' in filename or filename in {'.', '..'}:
    raise ValueError(f"非法笔记文件名: {filename!r}")
knowledge_path = self.BASE_DIR / domain / "knowledge" / filename
try:
    knowledge_path.parent.mkdir(parents=True, exist_ok=True)
    knowledge_path.write_text(content, encoding="utf-8")
except OSError as e:
    raise FileWriteError(f"无法保存知识笔记 {knowledge_path}: {e}") from e
Defensive patterns

Strategy: validation

Validate before calling

import re

SAFE_FILENAME = re.compile(r"^[\w\-]+\.(md|txt)$")

def valid_knowledge_filename(filename: str) -> bool:
    return bool(filename) and bool(SAFE_FILENAME.match(filename))

Type guard

def is_safe_filename(name: str) -> bool:
    return (
        isinstance(name, str)
        and name not in ('.', '..')
        and '/' not in name
        and '\\' not in name
        and name.strip() != ''
    )

Try / catch

try:
    fm.save_knowledge(domain, filename, content)
except FileWriteError as e:
    logger.error("knowledge save failed: %s/%s: %s", domain, filename, e)

Prevention

When it happens

Trigger: Calling save_knowledge before BASE_DIR/<domain>/knowledge/ exists; filename containing '/' causing an unexpected nested path or escape outside knowledge/; permission errors on the knowledge directory; filename being empty or '.' so the path resolves to a directory; disk full.

Common situations: Agent writes its first note for a newly created domain that only has plan.md; LLM-generated filename with slashes or Windows-style separators; read-only mount in production.

Related errors


AI-assisted analysis of datawhalechina/hello-agents@606a07d341 (2026-08-14). Data as JSON: /api/errors/dfe82586286472cd. Report an issue: GitHub.