usestrix/strix · error · SpecParseError
Unexpected Postman API response shape for {label}
Error message
Unexpected Postman API response shape for {label} What it means
SpecParseError raised when the Postman API returns valid JSON whose top level is not an object (e.g. a JSON array or bare string). The Postman REST API always wraps responses in an object, so this indicates a nonstandard intermediary or an API change.
Source
Thrown at strix/utils/api_spec.py:271
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)
if not isinstance(collection, dict) or not collection:
raise SpecParseError(f"Postman collection {collection_uid} came back empty")View on GitHub (pinned to 8551339130)
Solutions
- Print the raw response to see its actual shape: add a temporary dump or curl the endpoint directly
- Fix the mock/fixture to mirror the real envelope ({"collection": {...}})
- If Postman itself changed shape, pin to a local export until the tool is updated
Example fix
# before (mock returns)
[{"item": []}]
# after (mock returns the real envelope)
{"collection": {"info": {"_postman_id": "..."}, "item": []}} Defensive patterns
Strategy: type-guard
Validate before calling
payload = resp.json()
if not isinstance(payload, dict):
raise ValueError(f"expected object envelope, got {type(payload).__name__}: {str(payload)[:80]}") Type guard
def is_postman_envelope(p) -> bool:
return isinstance(p, dict) Try / catch
except SpecParseError as e:
if "response shape" in str(e):
fail loudly with the raw payload attached — this means a mock or gateway is broken, not a transient issue Prevention
- Make mocks replicate the real {"collection": ...} envelope
- Record and replay real Postman responses in tests instead of hand-writing fixtures
When it happens
Trigger: A mock/stub server standing in for the Postman API that returns a bare array; an API gateway stripping the envelope; Postman shipping a breaking format change.
Common situations: Local development against a mocked Postman API; HTTP interception tools returning canned fixtures.
Related errors
- Invalid API spec '{target}': {exc}
- Missing Postman collection id in '{target}' (expected postma
- {p} does not contain a mapping at the top level
- POSTMAN_API_KEY is not set. Export a Postman API key (PMAK-…
- Failed to reach the Postman API: {exc}
AI-assisted analysis of usestrix/strix@8551339130 (2026-08-15).
Data as JSON: /api/errors/5cf796e8563e347a.
Report an issue: GitHub.