datawhalechina/hello-agents · error · ValueError

无效的笔记格式:缺少YAML前置元数据

Error message

无效的笔记格式:缺少YAML前置元数据

What it means

ValueError from NoteTool._markdown_to_note when the markdown text does not begin with a '---\n...\n---\n' YAML frontmatter block (regex re.match with DOTALL anchors at position 0). Every stored note is round-tripped as frontmatter + body, so text lacking the leading delimiters cannot be parsed back into a note object.

Source

Thrown at Co-creation-projects/YYHDBL-HelloCodeAgentCli/tools/builtin/note_tool.py:154

            tags_str = json.dumps(note['tags'])
            frontmatter += f"tags: {tags_str}\n"
        frontmatter += f"created_at: {note['created_at']}\n"
        frontmatter += f"updated_at: {note['updated_at']}\n"
        frontmatter += "---\n\n"
        
        # Markdown内容
        content = f"# {note['title']}\n\n"
        content += note['content']
        
        return frontmatter + content
    
    def _markdown_to_note(self, markdown_text: str) -> Dict[str, Any]:
        """将Markdown文本解析为笔记对象"""
        # 提取YAML前置元数据
        frontmatter_match = re.match(r'^---\s*\n(.*?)\n---\s*\n', markdown_text, re.DOTALL)
        
        if not frontmatter_match:
            raise ValueError("无效的笔记格式:缺少YAML前置元数据")
        
        frontmatter_text = frontmatter_match.group(1)
        content_start = frontmatter_match.end()
        
        # 解析YAML(简化版)
        note = {}
        for line in frontmatter_text.split('\n'):
            if ':' in line:
                key, value = line.split(':', 1)
                key = key.strip()
                value = value.strip()
                
                # 处理特殊字段
                if key == 'tags':
                    try:
                        note[key] = json.loads(value)
                    except:
                        note[key] = []

View on GitHub (pinned to 606a07d341)

Solutions

  1. Ensure the note file starts, on line 1, with '---', then YAML keys, then a closing '---' before the body.
  2. Strip leading whitespace/BOM before parsing: markdown_text.lstrip('\ufeff').lstrip().
  3. If reading foreign markdown, skip note parsing or synthesize frontmatter (title/date) first.

Example fix

# before (parse fails)
text = '# My Note\n\nbody...'  
note = tool._markdown_to_note(text)

# after
text = '---\ntitle: My Note\ncreated: 2026-01-01\n---\n\n# My Note\n\nbody...'
note = tool._markdown_to_note(text)
Defensive patterns

Strategy: try-catch

Validate before calling

def has_frontmatter(md: str) -> bool:
    return bool(re.match(r'^---\s*\n.*?\n---\s*(\n|$)', md, re.DOTALL))

if not has_frontmatter(text):
    text = f'---\ntitle: untitled\n---\n\n{text}'  # or reject

Type guard

def is_note_markdown(md: str) -> bool:
    first = md.lstrip('\ufeff').splitlines()[0] if md.strip() else ''
    return first.strip() == '---'

Try / catch

try:
    note = tool._markdown_to_note(md)
except ValueError as e:
    if 'YAML' in str(e):
        md = f'---\ntitle: imported\n---\n\n{md}'
        note = tool._markdown_to_note(md)
    else:
        raise

Prevention

When it happens

Trigger: Calling the note tool's parse/read path with plain markdown that has no frontmatter; a leading blank line or BOM before the first '---' so re.match fails; frontmatter delimiters using '----' or missing the closing '---'.

Common situations: Users pasting raw markdown into a note-read/list operation; hand-edited note files where the frontmatter was deleted; files created by other tools (Obsidian requires exact '---' first line too); trailing spaces after '---' are tolerated by \s* but a preceding empty line is not.

Related errors


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