Skip to content

Latest commit

 

History

History
110 lines (84 loc) · 3.5 KB

File metadata and controls

110 lines (84 loc) · 3.5 KB

Error Handling Fixes Summary

This document consolidates the journey of fixing critical errors in the Substack MCP Plus project, particularly the "'str' object has no attribute 'get'" errors that affected multiple tools.

The Problem

Initial testing revealed that 5 out of 14 tools were failing with cryptic error messages:

  • update_post - Not persisting changes
  • get_post_content - Returning empty content
  • preview_draft - Not returning URLs
  • Multiple tools failing with: 'str' object has no attribute 'get'

The Journey

Round 1-2: Initial Misdiagnosis

What we thought: The python-substack library was returning string errors instead of proper exceptions.

What we did:

  • Created api_wrapper.py to handle string errors
  • Added defensive programming with type checking
  • Wrapped all API calls with error handling

Result: Errors persisted - we were solving the wrong problem.

Round 3-4: Infrastructure Building

What we learned: The library uses proper exceptions, not string errors.

What we did:

  • Enhanced error handling across all handlers
  • Added comprehensive logging
  • Created validation methods

Result: Better error messages, but core issues remained.

Round 5-7: Deeper Investigation

Discovery: Through testing with a known post (Homer Simpson post ID: 167669176), we found:

  • The tool was retrieving data successfully
  • But get_post_content showed empty content
  • Debug revealed: body field was a JSON string, not a dictionary

Round 8: The Breakthrough

The Real Problem: Substack stores post content as JSON strings, not parsed objects.

# What we expected:
post['body'] = {
    "type": "doc",
    "content": [...]
}

# What we actually got:
post['body'] = '{"type":"doc","content":[...]}'  # A string!

The Solution

1. JSON Parsing for Content

# In post_handler.py
if isinstance(body, str):
    try:
        body_data = json.loads(body)
    except json.JSONDecodeError:
        return body  # Return as-is if not JSON

2. Proper Text Extraction

The parsed JSON revealed text was stored in a 'text' field, not 'content':

# Wrong:
text = item.get('content', '')

# Correct:
text = item.get('text', '')

3. Support for Substack's Format

Added support for actual Substack JSON structure:

  • bullet_list (not bulleted-list)
  • list_item with nested paragraphs
  • image2 type with attrs.src
  • captionedImage with nested content array

Key Learnings

  1. Always verify assumptions: We assumed the API returned dictionaries, but some fields were JSON strings
  2. Debug with real data: Using actual post IDs revealed the true data structure
  3. Read the actual response: The library wasn't broken - we just weren't handling the data correctly
  4. Substack's content format:
    • Published posts: body field
    • Draft posts: draft_body field
    • Both store content as JSON strings that need parsing

Current Status

All tools now working correctly:

  • update_post - Persists changes properly
  • get_post_content - Returns full formatted content
  • preview_draft - Returns preview URLs
  • ✅ Content extraction - Handles all Substack content types
  • ✅ Error handling - Graceful degradation for unexpected formats

Remaining Known Issues

While these errors are fixed, some formatting limitations remain:

  • Text formatting (bold/italic) displays as markdown syntax
  • Links display as markdown syntax
  • Blockquotes show with > prefix

See KNOWN_ISSUES.md for current limitations.