Skip to content

Commit 90d746e

Browse files
fix: Handle dict objects in write_resource endpoint
Fixes #412 - 'dict' object has no attribute 'strip' error The production issue was caused by dict objects being passed to the write_resource endpoint instead of strings, which then caused AttributeError when file_utils tried to call .strip() on the content. Changes: - resource_router.py: Added defensive type checking to catch dict inputs early and return helpful 400 error with diagnostic info - canvas.py: Fixed to use content= parameter with text/plain content type instead of json= parameter, preventing double-encoding The canvas tool was using json=canvas_json where canvas_json was already a JSON string, which could cause encoding issues. The endpoint expects Body() string content, so we now send it as raw content. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-authored-by: Paul Hernandez <phernandez@users.noreply.github.com>
1 parent 021af74 commit 90d746e

2 files changed

Lines changed: 22 additions & 1 deletion

File tree

src/basic_memory/api/routers/resource_router.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,20 @@ async def write_resource(
151151
try:
152152
# Get content from request body
153153

154+
# Defensive type checking: ensure content is a string
155+
# FastAPI should validate this, but if a dict somehow gets through
156+
# (e.g., via JSON body parsing), we need to catch it here
157+
if isinstance(content, dict):
158+
logger.error(
159+
f"Error writing resource {file_path}: "
160+
f"content is a dict, expected string. Keys: {list(content.keys())}"
161+
)
162+
raise HTTPException(
163+
status_code=400,
164+
detail="content must be a string, not a dict. "
165+
"Ensure request body is sent as raw string content, not JSON object.",
166+
)
167+
154168
# Ensure it's UTF-8 string content
155169
if isinstance(content, bytes): # pragma: no cover
156170
content_str = content.decode("utf-8")

src/basic_memory/mcp/tools/canvas.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,14 @@ async def canvas(
110110

111111
# Write the file using the resource API
112112
logger.info(f"Creating canvas file: {file_path} in project {project}")
113-
response = await call_put(client, f"{project_url}/resource/{file_path}", json=canvas_json)
113+
# Send canvas_json as content string, not as json parameter
114+
# The resource endpoint expects Body() string content, not JSON-encoded data
115+
response = await call_put(
116+
client,
117+
f"{project_url}/resource/{file_path}",
118+
content=canvas_json,
119+
headers={"Content-Type": "text/plain"},
120+
)
114121

115122
# Parse response
116123
result = response.json()

0 commit comments

Comments
 (0)