{"record":{"id":"5967e5c220961843","repo":"MemPalace/mempalace","slug":"malformed-response-from-url-e","errorCode":null,"errorMessage":"Malformed response from {url}: {e}","messagePattern":"Malformed response from (.+?): (.+?)","errorType":"exception","errorClass":"LLMError","httpStatus":null,"severity":"error","filePath":"mempalace/llm_client.py","lineNumber":199,"sourceCode":"    req = Request(\n        url,\n        data=json.dumps(body).encode(\"utf-8\"),\n        headers={\"Content-Type\": \"application/json\", **headers},\n    )\n    try:\n        with urlopen(req, timeout=timeout) as resp:\n            return json.loads(resp.read())\n    except HTTPError as e:\n        detail = \"\"\n        try:\n            detail = e.read().decode(\"utf-8\", errors=\"replace\")[:500]\n        except Exception:\n            pass\n        raise LLMError(f\"HTTP {e.code} from {url}: {detail or e.reason}\") from e\n    except (URLError, OSError) as e:\n        raise LLMError(f\"Cannot reach {url}: {e}\") from e\n    except json.JSONDecodeError as e:\n        raise LLMError(f\"Malformed response from {url}: {e}\") from e\n\n\n# ==================== OLLAMA ====================\n\n\nclass OllamaProvider(LLMProvider):\n    name = \"ollama\"\n    DEFAULT_ENDPOINT = \"http://localhost:11434\"\n\n    def __init__(\n        self,\n        model: str,\n        endpoint: Optional[str] = None,\n        timeout: int = 180,\n        num_ctx: Optional[int] = None,\n        **_: object,\n    ):\n        super().__init__(","sourceCodeStart":181,"sourceCodeEnd":217,"githubUrl":"https://github.com/MemPalace/mempalace/blob/06cb6987f02610784fefbad4b2bd5d026d164ba6/mempalace/llm_client.py#L181-L217","documentation":"LLMError raised when the LLM endpoint returns HTTP 200 but the body is not valid JSON (json.JSONDecodeError). The provider pipeline assumes every successful response parses, so a non-JSON body — an HTML error page, a proxy login page, truncated output — surfaces here.","triggerScenarios":"A proxy or captive portal intercepting the request and returning HTML; an OpenAI-compatible server that returns plain-text errors with status 200; a response truncated by a gateway so the JSON is cut mid-string.","commonSituations":"Corporate proxies rewriting responses; pointing --llm-endpoint at a web UI instead of the API port (e.g. LM Studio UI port vs API port); reverse proxies (nginx/traefik) emitting error pages; version mismatch where the server changed its response format.","solutions":["curl the endpoint with the same payload and inspect the raw body — it is usually HTML/plain text, revealing the real culprit","Fix the endpoint URL to target the API server, not a web UI or proxy login page","Bypass or configure the intercepting proxy for this host","If the body is truncated JSON, check gateway/proxy response size limits"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"from mempalace.llm_client import LLMError\n\ntry:\n    resp = provider.classify(system, user)\nexcept LLMError as e:\n    if \"Malformed response\" in str(e):\n        # body was not JSON — dump context for debugging, do not blind-retry\n        log.error(\"non-JSON response from %s — check proxy/gateway\", provider.endpoint)\n        raise","preventionTips":["Verify the endpoint returns JSON with a one-off curl before wiring it in","Exclude LLM endpoints from HTML-rewriting proxies and captive portals","Pin server versions whose response format you have tested"],"tags":["network","llm","json","proxy","http"],"backgroundTag":null,"analyzedSha":"06cb6987f02610784fefbad4b2bd5d026d164ba6","analyzedAt":"2026-08-15T03:03:36.213Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}