usestrix/strix · error · SpecParseError

Postman API returned non-JSON for {label}

Error message

Postman API returned non-JSON for {label}

What it means

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.

Source

Thrown at strix/utils/api_spec.py:269

            url,
            headers={"X-Api-Key": api_key, "Accept": "application/json"},
            timeout=_POSTMAN_FETCH_TIMEOUT,
        )
    except requests.RequestException as exc:
        raise SpecParseError(f"Failed to reach the Postman API: {exc}") from exc

    if response.status_code == 401:
        raise SpecParseError("Postman API rejected the key (401). Check POSTMAN_API_KEY.")
    if response.status_code == 404:
        raise SpecParseError(
            f"Postman {label} not found (404). Check the id and that the key can access it.",
        )
    if response.status_code != 200:
        raise SpecParseError(f"Postman API returned HTTP {response.status_code} for {label}.")
    try:
        payload = response.json()
    except ValueError as exc:
        raise SpecParseError(f"Postman API returned non-JSON for {label}") from exc
    if not isinstance(payload, dict):
        raise SpecParseError(f"Unexpected Postman API response shape for {label}")
    return payload


def fetch_postman_collection(collection_uid: str, api_key: str) -> dict[str, Any]:
    """Fetch a collection from the Postman API and return the raw collection dict.

    Uses ``GET /collections/{uid}`` with the ``X-Api-Key`` header. The endpoint
    wraps the collection under a ``collection`` key, unwrapped here so the result
    matches an exported collection file.
    """
    payload = _postman_api_json(
        f"{POSTMAN_API_BASE}/collections/{collection_uid}",
        api_key,
        f"collection {collection_uid}",
    )
    collection = payload.get("collection", payload)

View on GitHub (pinned to 8551339130)

Solutions

  1. Inspect what actually arrives: curl -sH "X-Api-Key: $K" https://api.getpostman.com/me | head
  2. Bypass or configure the proxy correctly (trust the proxy CA, disable content rewriting for api.getpostman.com)
  3. Fall back to a manual export downloaded from the Postman app

Example fix

# before: proxied env mangles the body
# after: pin direct egress for the API host
export NO_PROXY=api.getpostman.com
export HTTPS_PROXY=""
Defensive patterns

Strategy: try-catch

Validate before calling

resp = requests.get(url, headers={"X-Api-Key": key}, timeout=30)
try:
    resp.json()
except ValueError:
    raise ValueError(f"non-JSON body ({resp.headers.get('Content-Type')}): {resp.text[:120]!r}")

Try / catch

except SpecParseError as e:
    if "returned non-JSON" in str(e):
        dump resp.text via e.__cause__ context, check proxy/captive portal config, then retry once after fixing the network path

Prevention

When it happens

Trigger: A transparent proxy returning an HTML login page with 200; a captive portal on conference/hotel Wi-Fi; response compression mishandled by a middleware.

Common situations: Corporate proxies intercepting HTTPS with content rewriting; misconfigured local mitmproxy; CDN/edge corruption.

Related errors


AI-assisted analysis of usestrix/strix@8551339130 (2026-08-15). Data as JSON: /api/errors/d265d73677cd41e5. Report an issue: GitHub.