{"record":{"id":"d265d73677cd41e5","repo":"usestrix/strix","slug":"postman-api-returned-non-json-for-label","errorCode":null,"errorMessage":"Postman API returned non-JSON for {label}","messagePattern":"Postman API returned non-JSON for (.+?)","errorType":"exception","errorClass":"SpecParseError","httpStatus":null,"severity":"error","filePath":"strix/utils/api_spec.py","lineNumber":269,"sourceCode":"            url,\n            headers={\"X-Api-Key\": api_key, \"Accept\": \"application/json\"},\n            timeout=_POSTMAN_FETCH_TIMEOUT,\n        )\n    except requests.RequestException as exc:\n        raise SpecParseError(f\"Failed to reach the Postman API: {exc}\") from exc\n\n    if response.status_code == 401:\n        raise SpecParseError(\"Postman API rejected the key (401). Check POSTMAN_API_KEY.\")\n    if response.status_code == 404:\n        raise SpecParseError(\n            f\"Postman {label} not found (404). Check the id and that the key can access it.\",\n        )\n    if response.status_code != 200:\n        raise SpecParseError(f\"Postman API returned HTTP {response.status_code} for {label}.\")\n    try:\n        payload = response.json()\n    except ValueError as exc:\n        raise SpecParseError(f\"Postman API returned non-JSON for {label}\") from exc\n    if not isinstance(payload, dict):\n        raise SpecParseError(f\"Unexpected Postman API response shape for {label}\")\n    return payload\n\n\ndef fetch_postman_collection(collection_uid: str, api_key: str) -> dict[str, Any]:\n    \"\"\"Fetch a collection from the Postman API and return the raw collection dict.\n\n    Uses ``GET /collections/{uid}`` with the ``X-Api-Key`` header. The endpoint\n    wraps the collection under a ``collection`` key, unwrapped here so the result\n    matches an exported collection file.\n    \"\"\"\n    payload = _postman_api_json(\n        f\"{POSTMAN_API_BASE}/collections/{collection_uid}\",\n        api_key,\n        f\"collection {collection_uid}\",\n    )\n    collection = payload.get(\"collection\", payload)","sourceCodeStart":251,"sourceCodeEnd":287,"githubUrl":"https://github.com/usestrix/strix/blob/85513391305171ecc6faffe03da4a8bda5e3febb/strix/utils/api_spec.py#L251-L287","documentation":"SpecParseError raised when the Postman API returns HTTP 200 but the body is not valid JSON — response.json() raises ValueError, which is chained. Rare on Postman's side; usually caused by an intermediary (proxy, captive portal) rewriting the response.","triggerScenarios":"A transparent proxy returning an HTML login page with 200; a captive portal on conference/hotel Wi-Fi; response compression mishandled by a middleware.","commonSituations":"Corporate proxies intercepting HTTPS with content rewriting; misconfigured local mitmproxy; CDN/edge corruption.","solutions":["Inspect what actually arrives: curl -sH \"X-Api-Key: $K\" https://api.getpostman.com/me | head","Bypass or configure the proxy correctly (trust the proxy CA, disable content rewriting for api.getpostman.com)","Fall back to a manual export downloaded from the Postman app"],"exampleFix":"# before: proxied env mangles the body\n# after: pin direct egress for the API host\nexport NO_PROXY=api.getpostman.com\nexport HTTPS_PROXY=\"\"","handlingStrategy":"try-catch","validationCode":"resp = requests.get(url, headers={\"X-Api-Key\": key}, timeout=30)\ntry:\n    resp.json()\nexcept ValueError:\n    raise ValueError(f\"non-JSON body ({resp.headers.get('Content-Type')}): {resp.text[:120]!r}\")","typeGuard":null,"tryCatchPattern":"except SpecParseError as e:\n    if \"returned non-JSON\" in str(e):\n        dump resp.text via e.__cause__ context, check proxy/captive portal config, then retry once after fixing the network path","preventionTips":["Trust the corporate proxy CA bundle (REQUESTS_CA_BUNDLE) instead of disabling verification","Exclude api.getpostman.com from content-rewriting proxies (NO_PROXY)","Smoke-test with curl before wiring into automation"],"tags":["postman","parsing","proxy"],"backgroundTag":null,"analyzedSha":"85513391305171ecc6faffe03da4a8bda5e3febb","analyzedAt":"2026-08-15T05:03:57.275Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}