-
Notifications
You must be signed in to change notification settings - Fork 180
edit_note fails on notes with long text around inline wikilinks (relation_type exceeds MaxLen) #721
Description
Summary
edit_note silently fails on notes where inline wikilinks have long surrounding text (~180+ chars). The note becomes "poisoned" — reads work fine, but all subsequent edit_note calls fail with a validation error during re-indexing.
Reproduction
- Create a note with a long descriptive bullet containing an inline wikilink:
- **Lorem ipsum dolor sit amet** — consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Trust boundary model documented in [[Some Note Title]] for additional context on the architectural design patterns.The text preceding [[Some Note Title]] must exceed 200 characters. The relation_type is extracted from the text before the wikilink — text after the wikilink doesn't matter. ~193 chars before the link passes; ~260 chars fails.
- Let the file watcher index the note (or create via
write_note— both work) - Call
edit_noteon this note (any operation — append, find_replace, etc.) - Edit fails with:
1 validation error for EntityResponseV2
relations.0.relation_type
String should have at most 200 characters [type=string_too_long, input_value='**Lorem ipsum dolor sit ...boundary model found in', input_type=str]
- All subsequent
edit_notecalls on this note fail with the same error
Root Cause
In src/basic_memory/models/knowledge.py, the Observation.permalink property truncates content to 200 chars:
content_for_permalink = self.content[:200] if len(self.content) > 200 else self.contentIn src/basic_memory/markdown/plugins.py, parse_relation() (line 98) extracts the relation type by taking ALL text before [[:
# Line 113-116
before = content[:start].strip()
if before:
rel_type = beforeThis works for intended usage: - reports_to [[Jane Smith]] → rel_type = "reports_to". But when a prose sentence contains an inline wikilink: - Long descriptive text here... See [[Some Note]] → rel_type = "Long descriptive text here... See".
The Pydantic model EntityResponseV2 in schemas/base.py enforces MaxLen(200) on relation_type. When preceding prose exceeds 200 chars, validation fails. Text after the wikilink is not the issue.
The error occurs during re-indexing (sync), not during file write. The file may already be written to disk, leaving the note in an inconsistent state — file updated, database not. Every subsequent edit_note triggers the same re-index failure because the problematic line still exists.
Expected Behavior
edit_note should handle long text around inline wikilinks gracefully.
Recommended Fix
In parse_relation(), detect when before text is prose (not a semantic relation label) and fall back to links_to:
# Line 113-116, current:
before = content[:start].strip()
if before:
rel_type = before
# Proposed fix:
before = content[:start].strip()
if before and len(before) <= 50 and " " not in before.strip("_-"):
rel_type = before # Short label like "reports_to", "evidence"
# else: keep default rel_type = "relates_to" (prose with embedded link)The heuristic: semantic relation labels are short (~50 chars max), typically single words or snake_case. Prose sentences containing wikilinks have spaces, punctuation, markdown formatting. Falling back to the default type for prose preserves the link without using prose as a relation_type.
Additionally, as a safety net: catch the Pydantic MaxLen validation error per-relation and skip the problematic relation rather than failing the entire edit. This prevents note poisoning even if the heuristic misses an edge case.
Impact
- Notes are silently poisoned with no visible symptom until an edit is attempted
- The only recovery is a direct file edit (bypassing MCP) to shorten text around wikilinks, then trigger re-index
- Affects any note with descriptive prose containing inline wikilinks (common in design docs, meeting notes, project descriptions)
Environment
- basic-memory: latest (as of April 2026)
- macOS, SQLite backend (not PostgreSQL)
- Discovered via Claude Code MCP usage