{"record":{"id":"aa31c3ec31868a30","repo":"BerriAI/litellm","slug":"cisco-ai-defense-surface-api-returned-a-non-json","errorCode":null,"errorMessage":"Cisco AI Defense {surface} API returned a non-JSON response","messagePattern":"Cisco AI Defense (.+?) API returned a non-JSON response","errorType":"exception","errorClass":"CiscoAIDefenseGuardrailAPIError","httpStatus":null,"severity":"error","filePath":"litellm/proxy/guardrails/guardrail_hooks/cisco_ai_defense/cisco_ai_defense.py","lineNumber":843,"sourceCode":"            body_snippet = \"\"\n            try:\n                body_snippet = exc.response.text[:500] if exc.response else \"\"\n            except Exception:\n                body_snippet = \"\"\n            raise CiscoAIDefenseGuardrailAPIError(\n                f\"Cisco AI Defense {surface} API returned HTTP {status_code}: {body_snippet}\"\n            ) from exc\n        except httpx.TimeoutException as exc:\n            raise CiscoAIDefenseGuardrailAPIError(\n                f\"Cisco AI Defense {surface} API call timed out after {self.timeout}s\"\n            ) from exc\n        except httpx.RequestError as exc:\n            raise CiscoAIDefenseGuardrailAPIError(f\"Cisco AI Defense {surface} API request failed: {exc}\") from exc\n\n        try:\n            return response.json()\n        except ValueError as exc:\n            raise CiscoAIDefenseGuardrailAPIError(\n                f\"Cisco AI Defense {surface} API returned a non-JSON response\"\n            ) from exc\n\n    def _build_headers(self) -> dict[str, str]:\n        return {\n            CISCO_API_KEY_HEADER: self.api_key,\n            \"Content-Type\": \"application/json\",\n            \"Accept\": \"application/json\",\n            \"User-Agent\": f\"litellm/{litellm_version}\",\n        }\n\n    def _build_metadata(\n        self,\n        request_data: dict,\n        user_api_key_dict: UserAPIKeyAuth,\n    ) -> dict[str, object]:\n        metadata: Final[dict[str, object]] = {}\n","sourceCodeStart":825,"sourceCodeEnd":861,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/proxy/guardrails/guardrail_hooks/cisco_ai_defense/cisco_ai_defense.py#L825-L861","documentation":"CiscoAIDefenseGuardrailAPIError raised when a Cisco AI Defense response with a 2xx status has a body that response.json() cannot parse (httpx raises ValueError). This means the endpoint answered but did not return JSON — typically an HTML error/interstitial page from a proxy, captive portal, or load balancer sitting in front of the real API.","triggerScenarios":"CISCO_AI_DEFENSE_API_BASE pointing at a generic web server or auth portal that returns HTML 200; corporate proxies rewriting responses; a misrouted gateway that serves a landing page on the inspection path; empty bodies from some middleboxes.","commonSituations":"Custom api_base set to a domain whose root serves HTML; Zscaler/ Netsuite-style portals intercepting requests; api_base missing the API path prefix so the server returns its index page; rare occurrences when a CDN serves an error page with 200.","solutions":["curl the exact inspection URL from the proxy host and inspect Content-Type — it must be application/json.","Correct CISCO_AI_DEFENSE_API_BASE to the full API endpoint (or unset it to use CISCO_DEFAULT_API_BASE).","Bypass HTML-injecting middleboxes for the Cisco domain, or fix the proxy policy.","Enable fallback_on_error: allow so a poisoned response path degrades to unscanned-but-logged instead of erroring."],"exampleFix":"# before — base points at an HTML portal\nlitellm_params:\n  guardrail: cisco_ai_defense\n  api_base: https://cisco-gw.internal.example.com\n\n# after — official endpoint\nlitellm_params:\n  guardrail: cisco_ai_defense\n  # api_base omitted -> CISCO_DEFAULT_API_BASE","handlingStrategy":"validation","validationCode":"import httpx, os\nbase = os.environ.get(\"CISCO_AI_DEFENSE_API_BASE\")\nif base:\n    r = httpx.get(base, timeout=5)\n    ctype = r.headers.get(\"content-type\", \"\")\n    assert \"json\" in ctype or r.status_code in (401, 403, 404), (\n        f\"api_base returns {ctype} status={r.status_code} — probably not the inspection API\")","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Prefer the default Cisco API base; only override with a verified JSON endpoint.","Content-Type smoke checks in deploy pipelines catch HTML-portal interception early.","Exclude the Cisco API domain from HTML-injecting proxies (Zscaler-like) by policy."],"tags":["litellm","guardrails","cisco-ai-defense","json","response-parsing","proxy"],"backgroundTag":"invalid-json-response","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}