Errors
Prism is a GraphQL API, so errors arrive two ways: HTTP status codes for transport- and auth-level problems, and a GraphQL errors array (inside an otherwise-200 response) for problems with the query itself.
HTTP errors
| Status | Meaning | Cause / fix |
|---|---|---|
401 Unauthorized | Invalid or missing token | Send a valid Authorization: Bearer <token>. Get one from the Tokens endpoint; see Authentication. |
403 Forbidden | Token is valid but lacks the required scopes | Confirm the token is for the right account; contact your advocate if it persists. |
The token endpoint (POST /v1/users/token) can also return 415 Unsupported Media Type (the Content-Type isn't application/x-www-form-urlencoded) and 422 Unprocessable Entity (a required field is missing).
GraphQL errors
A request that authenticates but has a problem with the query returns 200 OK with an errors array, per the GraphQL spec — so check errors even on a 200 response:
{
"errors": [
{ "message": "Cannot query field \"foo\" on type \"Offer\"." }
],
"data": null
}
Common causes: requesting a field that doesn't exist, omitting a required argument (such as player_id), or a malformed query. GraphQL is introspective, so you can confirm valid queries and fields from any GraphQL client.
Validation errors
Arguments that are the right type but the wrong value fail validation. Unlike the
query errors above, these are field errors: they are raised while the field is being
resolved, so the field resolves to null and data stays an object.
{
"errors": [
{
"message": "Validation failed for the field [offers].",
"path": ["offers"],
"extensions": {
"validation": {
"player_id": [
"The player id field must not be greater than 255 characters."
]
}
}
}
],
"data": { "offers": null }
}
data === nulldata is null only for the pre-execution query errors in the section above. A validation
failure returns 200 OK with data present and the failing field set to null, so code
that treats data === null as "the request failed" will miss every validation error.
Check for a non-empty errors array instead, and use each error's path to identify which
field failed.
One error per field, not per argument
All of a single field's invalid arguments collapse into one error, with every reason in
that error's validation map:
{ offers(player_id: "abc", limit: 0, language: "toolong", sort: "bogus.sideways") { id } }
returns one error whose validation holds sort, limit, and language together.
Querying two fields that both fail returns two errors, one per field, each with its own
path — so iterate errors[] rather than reading errors[0], and read extensions.validation
rather than matching on message.
Rules by argument
| Argument | Rule | Error |
|---|---|---|
player_id | Required, non-empty, 255 characters or fewer | The player id field must not be greater than 255 characters. |
sort | Must be dot separated: one of epc.asc, epc.desc, last_activation.asc, last_activation.desc | Not dot separated: The selected sort is invalid, it must be a dot separated string specifying sort option and direction. Unknown option: ...the provided sort option (bogus) is invalid. Unknown direction: ...the provided direction (sideways) is invalid. |
limit | Integer, 1 or greater | The limit field must be at least 1. |
language | 2 to 5 characters | The language field must not be greater than 5 characters. |
The rules above apply to offers. links takes only player_id, so the first row is the whole
of its validation.
playerOffers
playerOffers applies the same player_id and language rules. Its limit is capped rather
than open-ended, and it adds after:
| Argument | Rule | Error |
|---|---|---|
limit | Integer, 1 to 100. Defaults to 50 when omitted | The limit field must not be greater than 100. |
after | Optional. Must be a next_cursor value from an earlier playerOffers response | See Invalid pagination cursor |
Invalid pagination cursor
playerOffers paginates with an opaque cursor. Passing an after value the query did not issue
is reported as an error rather than quietly restarting at the first page, because a silent reset
is indistinguishable to the caller from a list that never ends.
Unlike the validation failures above, this arrives without an extensions.validation map. The
caller-facing explanation is in extensions.reason:
{
"errors": [
{
"message": "An error occurred while fetching player offers",
"path": ["playerOffers"],
"extensions": {
"reason": "The `after` cursor is not one this query issued. Omit it to start from the first page."
}
}
],
"data": { "playerOffers": null }
}
Cursors are opaque and only meaningful to the query that issued them. Read next_cursor from the
previous response and pass it back unchanged, rather than building or editing one yourself.
Prism validates argument types and lengths only. It does not enforce the player ID character or casing conventions — see Player ID for those, and why they still matter.