Errors
GraphQL reports errors in the response body, next to whatever data could still be returned. Check the errors array on every response.
The shape of an error#
A request that reached GraphQL is answered with HTTP 200, whether or not it
succeeded. Errors are listed in errors; each names the field that failed in
path.
Here a key with catalog_read but not media_read asks for a track list
with download URLs:
{
"data": {
"release": {
"title": "Paper Radio",
"resources": [
{ "title": "Signal Fire", "url": null },
{ "title": "Paper Radio", "url": null }
]
}
},
"errors": [
{
"message": "credential lacks the MediaRead scope",
"locations": [{ "line": 5, "column": 7 }],
"path": ["release", "resources", 0, "url"]
},
{
"message": "credential lacks the MediaRead scope",
"locations": [{ "line": 5, "column": 7 }],
"path": ["release", "resources", 1, "url"]
}
]
}The titles resolved; each url did not. This is ordinary GraphQL
behavior: one failing field does not void the request. When a failing field
is non-nullable, the null travels up to the nearest nullable parent — for a
root field, that can make data itself null.
| Field | Meaning |
|---|---|
message | What went wrong, for a developer. Stable enough to log, not to parse. |
path | The field that failed, from the root. |
locations | Line and column in your query. |
extensions.code | Present on some errors — see below. Switch on this when it exists. |
Errors before execution#
If the query cannot be run at all, data is null and nothing executed.
| Cause | Example message |
|---|---|
| Syntax error | A parser message with the line and column |
| Unknown field or argument | Unknown field "titel" on type "Release". |
| Wrong argument type | Invalid value for argument … |
| Too deep | Query is nested too deep. (limit 12) |
| Too complex | Query is too complex. (limit 500 fields) |
Validate queries against schema.graphql at build time and
you will not meet these in production.
Authentication errors#
extensions.code | Message | Meaning |
|---|---|---|
UNAUTHENTICATED | not authenticated: present a bearer token in the Authorization header | No credential was sent. |
UNAUTHENTICATED | invalid or expired credential | A credential was sent and rejected. The reason is deliberately not given. |
Authorization errors#
credential lacks the <Scope> scope — the credential is valid but lacks a
scope this field needs. The scope is named in the style of
Viewer.scopes (CatalogRead); its wire spelling is
catalog_read. See what each operation requires.
Not found is not an error#
Asking for something that does not exist, or that is not in your catalog,
usually returns null or false rather than an error — and the two cases are
indistinguishable on purpose, so that an API key cannot probe for other
customers' data.
| Operation | Not found returns |
|---|---|
| release, draftRelease | null |
| removeResource, discardBlockedRelease, removeOrgMember | false |
| deliveryAccountKeys | [] |
| updateRelease | error no such release in this catalog |
| requestUpload, completeUpload | error no resource <id> in this catalog |
Validation problems are data#
publishRelease does not use errors for "this
release is not ready yet". It returns published: false and a list of every
problem, so you can show them all at once:
{
"data": {
"publishRelease": {
"published": false,
"problems": [
"a UPC or GRid is required to publish",
"no cover art"
]
}
}
}Common errors#
| Message | From | What to do |
|---|---|---|
those bytes are not in the store: complete the upload first, or request a new URL if it expired | completeUpload, deliverMessage, deliverFile | The PUT did not finish or its URL expired. Request a new upload and retry. |
<n> bytes exceeds the 5368709120-byte single-upload limit; deliver files this large over SFTP | requestUpload, requestDeliveryUpload | Use SFTP for files over 5 GiB. |
byteSize must be positive | requestUpload, requestDeliveryUpload | Send the real file size. |
ERN parse error: … / ERN map error: … | deliverMessage | The XML is not a DDEX ERN //SCHEMA can read. The message says where. |
unknown scope "…" | mintApiKey | Use the wire spelling, e.g. catalog_read. |
cannot grant "…": this credential does not hold it, … | mintApiKey | A key cannot mint a more powerful key. |
only an owner can make somebody else an owner | addOrgMember, setOrgMemberRole | Ask an owner. |
you cannot change your own role — ask another owner or admin to do it | setOrgMemberRole | As it says. The same applies to removing yourself. |
… is a private, loopback or reserved address, which webhooks cannot be sent to | createWebhookEndpoint, updateWebhookEndpoint | Use a public https:// URL. |
webhook URLs must use https:// / … the default HTTPS port (443) | createWebhookEndpoint, updateWebhookEndpoint | Serve your receiver over HTTPS on port 443. |
unknown event type "…"; see webhookEventTypes | createWebhookEndpoint, updateWebhookEndpoint | Use a type from webhookEventTypes. |
an organization can have at most 10 webhook endpoints | createWebhookEndpoint | Delete one you no longer use. |
no owner of this organization has an email address we can send to, … | createWebhookEndpoint, updateWebhookEndpoint | Every owner is told about a new webhook destination; give an owner a working address. |
the endpoint is disabled; enable it first | sendTestWebhook, redeliverWebhook | Turn it back on with updateWebhookEndpoint. |
media is not available: this deployment has no object store configured | Resource.url, Message.sourceUrl | A server-side configuration problem; contact support. |
cannot presign: ttl must be between 1s and 3600s, got 0s | Resource.url, Message.sourceUrl | Pass a positive ttlSeconds, or omit it. |
code ENCODING_PENDING, ENCODING_NOT_REQUESTED, ENCODING_NOT_AVAILABLE, ENCODING_FAILED, UNKNOWN_ENCODING | Resource.url, requestEncoding | See Encodings and media URLs. |
code LOSSLESS_NOT_ENABLED | Resource.url, requestEncoding | Your organization does not have lossless media — it comes with enterprise, and with other plans by arrangement. Pull a lossy encoding such as aac-256. |
lossless media is not enabled for this organization | mintApiKey | media_lossless can only be put on a key in an organization with lossless media. |
code LOSSY_MASTER: MP3 is not accepted as a master: … | deliverFile, completeUpload | Masters must be lossless — WAV, AIFF, FLAC or ALAC — decided from the file's header. A refused delivery is listed by deliveryRejections. |
Retrying#
Most mutations are safe to retry after a network failure: publishing, delivering a message, delivering a file, completing an upload, revoking a key and removing a resource all converge on the same result when repeated. Minting a key, issuing a delivery account, adding a resource and creating a party without a DPID are not — retrying them creates a second one.