Skip to content

[Bug] clean_json_response crashes with cryptic AttributeError when given None #1525

@Ptah-CT

Description

@Ptah-CT

Summary

clean_json_response(response) in src/memos/mem_os/utils/format_utils.py:1393 calls response.replace(...) unconditionally. When response is None it dies with:

AttributeError: 'NoneType' object has no attribute 'replace'

The traceback points to format_utils.py:1403 and gives no hint about the real problem (an upstream LLM call returning None).

How None reaches here

In the codebase today this is reachable via the suggestion endpoint:

POST /product/suggestions
→ suggestion_handler.handle_get_suggestion_queries
→ llm.generate(message_list)            # OpenAILLM.generate, decorated with @timed_with_status
→ (LLM call raises BadRequestError)
→ timed_with_status catches, no fallback configured, falls through to implicit `return None`
→ clean_json_response(None)
→ AttributeError ← user sees this

The deeper bug is in timed_with_status (filed separately as #1523). Even after that is fixed, however, defending against None here is cheap and turns the worst possible diagnostic experience (a wrong-line AttributeError) into a clear message that names the actual root cause.

Proposed fix

if response is None:
    raise ValueError(
        "clean_json_response received None — upstream LLM call likely "
        "failed silently (check timed_with_status / generate() error handling)."
    )
return response.replace("```json", "").replace("```", "").strip()

PR follows.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions