{"record":{"id":"7e7bd78b5877679b","repo":"ATH-MaaS/Pixelle-Video","slug":"failed-to-parse-llm-response-as-response-type-n","errorCode":null,"errorMessage":"Failed to parse LLM response as {response_type.__name__}: {content[:200]}...","messagePattern":"Failed to parse LLM response as (.+?): (.+?)\\.\\.\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"pixelle_video/services/llm_service.py","lineNumber":330,"sourceCode":"        if match:\n            try:\n                data = json.loads(match.group(1))\n                return response_type.model_validate(data)\n            except json.JSONDecodeError:\n                pass\n        \n        # Try to find any JSON object in the text\n        brace_start = content.find('{')\n        brace_end = content.rfind('}')\n        if brace_start != -1 and brace_end > brace_start:\n            try:\n                json_str = content[brace_start:brace_end + 1]\n                data = json.loads(json_str)\n                return response_type.model_validate(data)\n            except json.JSONDecodeError:\n                pass\n        \n        raise ValueError(f\"Failed to parse LLM response as {response_type.__name__}: {content[:200]}...\")\n    \n    @property\n    def active(self) -> str:\n        \"\"\"\n        Get active model name\n        \n        Returns:\n            Active model name\n        \n        Example:\n            print(f\"Using model: {pixelle_video.llm.active}\")\n        \"\"\"\n        return self._get_config_value(\"model\", \"gpt-3.5-turbo\")\n    \n    def __repr__(self) -> str:\n        \"\"\"String representation\"\"\"\n        model = self.active\n        base_url = self._get_config_value(\"base_url\", \"default\")","sourceCodeStart":312,"sourceCodeEnd":348,"githubUrl":"https://github.com/ATH-MaaS/Pixelle-Video/blob/848b054e4fae40dabc62ec58e960b573e83793ac/pixelle_video/services/llm_service.py#L312-L348","documentation":"LLMService._parse_response_as_model tries three ways to recover JSON from the LLM's raw text — direct json.loads, a ```json fenced block, and a brace-substring extraction — then validates with response_type.model_validate (Pydantic). If none parse as JSON it raises ValueError naming the target model type and a 200-char snippet of the content.","triggerScenarios":"Calling _call_with_structured_output with a Pydantic model and the model returned prose, a refusal, truncated JSON, or JSON with trailing text that broke parsing; note that JSONDecodeError is caught but Pydantic ValidationError propagates differently, so this specifically means 'no parseable JSON object found'.","commonSituations":"Small/cheap model that ignores the JSON instruction; response truncated by max_tokens mid-object; model wraps JSON in prose or emits single quotes/JS-style literals; safety refusal instead of data.","solutions":["Strengthen the prompt: demand strict JSON only, no prose, and provide the schema inline or via function-calling/JSON mode","Increase max_tokens so the JSON is not truncated mid-object","Use a provider-native structured-output/JSON mode or function calling instead of prompt-based JSON","Retry with a fallback model that follows JSON instructions reliably","Loosen/repair parsing (e.g. strip trailing commas, use json-repair) before failing"],"exampleFix":"// before\ntext = await llm.generate(prompt)\nscene = Scene.model_validate_json(text)  # may raise ValueError\n// after\nprompt = base_prompt + \"\\nRespond with ONLY a JSON object matching the schema. No markdown, no commentary.\"\ntry:\n    scene = await llm.parse(prompt, Scene)  # structured output mode\nexcept ValueError:\n    scene = await fallback_llm.parse(prompt, Scene)","handlingStrategy":"retry","validationCode":"import json, re\ndef looks_like_json(content: str) -> bool:\n    m = re.search(r'\\{[\\s\\S]*\\}', content)\n    if not m:\n        return False\n    try:\n        json.loads(m.group(0))\n        return True\n    except json.JSONDecodeError:\n        return False","typeGuard":"def is_parseable_as(content: str, model) -> bool:\n    from pydantic import ValidationError\n    m = re.search(r'\\{[\\s\\S]*\\}', content)\n    if not m:\n        return False\n    try:\n        model.model_validate(json.loads(m.group(0)))\n        return True\n    except (json.JSONDecodeError, ValidationError):\n        return False","tryCatchPattern":"for attempt in range(3):\n    try:\n        return await llm.parse(prompt, Scene)\n    except ValueError:\n        prompt += \"\\nIMPORTANT: reply with a single valid JSON object only.\"\nraise RuntimeError(\"LLM never returned parseable JSON\")","preventionTips":["Use provider JSON mode / function calling / structured outputs when available","Set max_tokens high enough that JSON objects are never truncated","Include the exact JSON schema in the prompt and one worked example","Prefer models known to follow formatting instructions for structured tasks"],"tags":["python","llm","json-parsing","pydantic"],"backgroundTag":"llm-output-not-valid-json","analyzedSha":"848b054e4fae40dabc62ec58e960b573e83793ac","analyzedAt":"2026-08-30T03:24:41.468Z","schemaVersion":2},"datasetVersion":"2026-08-30T08:17:16.595Z"}