Appearance
Errors
The ArtistHub API answers 200 OK for almost everything, including failures. GraphQL reports problems in the errors array of the response body. Always inspect errors before you trust data.
json
{
"data": null,
"errors": [
{
"extensions": { "code": "validation-failed", "path": "$.selectionSet.links" },
"message": "field 'links' not found in type: 'query_root'"
}
]
}A partial success is possible: data may contain some fields while errors describes others that failed. Do not assume data === null on error.
Error codes
| Code | Where it comes from | Meaning |
|---|---|---|
validation-failed | GraphQL engine | The document references a field, argument, or type that does not exist for your role. Usually a missing token. |
invalid-jwt | GraphQL engine | The authorization token is malformed, truncated, or not signed by ArtistHub. |
invalid-headers | GraphQL engine | The authorization header is present but unparseable. |
constraint-violation | Database | A write violated a unique or foreign-key constraint — for example a domain + path pair that already exists. |
permission-error | Database | The write targeted a column your role is not allowed to set. See the per-page column allowlists. |
not-supported | GraphQL engine | The operation is not available, such as sending GET or subscribing to a table without subscription support. |
INTERNAL_SERVER_ERROR | Custom resolver | A hand-written resolver raised an error. The message is a plain-language description meant to be read. |
Reading validation-failed
This one code covers two very different situations.
You are not authenticated. Without a valid token the request runs as anonymous, and the anonymous schema contains almost nothing. The engine correctly reports that links does not exist, because for that role it does not.
json
{ "extensions": { "code": "validation-failed", "path": "$.selectionSet.links" },
"message": "field 'links' not found in type: 'query_root'" }Your document is genuinely wrong. A misspelled field, a missing required argument, or a wrong variable type produces the same code with a different path.
The path tells you which. $.selectionSet.<field> on a field you know exists means check your header first.
Reading resolver errors
Custom resolvers (login, create_link, quick_create_link, claim_number, and the rest) surface INTERNAL_SERVER_ERROR with a human-readable message. These are the messages worth handling explicitly:
| Message | Raised by | Cause |
|---|---|---|
Invalid email or password. | login | Unknown email or wrong password. |
This account is disabled. | login | Account deactivated. |
Authentication required. | any authenticated resolver | No authorization header reached the resolver. |
Invalid type | create_link | type was not bio, release, or playlist. |
Invalid spotify link for bio | create_link | A bio link needs an open.spotify.com/artist/... URL. |
Invalid spotify link for release | create_link | A release link needs an album or track URL. |
Invalid spotify link for playlist | create_link | A playlist link needs a playlist URL. |
Artist not found or user does not have access to the artist | create_link | Wrong artist_id, or your account is not attached to that artist. |
Invalid domain or path | create_link, path_available | domain failed hostname validation, or path was empty. |
Path must be 3 at least characters. | create_link, path_available | path is shorter than three characters. |
Artist does not have access to the domain | create_link | A custom domain was used that is not assigned to this artist. |
Path is not available | create_link | That domain + path pair is already taken. |
Autoplay track is only available for playlists | create_link | autoplay_track was sent for a non-playlist link. |
Autoplay track not found in the playlist | create_link | The track ID is not in the referenced Spotify playlist. |
No access. | link_stats | The link belongs to an artist you are not attached to. |
Empty results are not errors
Because row-level permissions filter silently, requesting a resource you do not own returns an empty result, not an error.
json
{ "data": { "links_by_pk": null } }means either "no such link" or "not yours" — the API deliberately does not distinguish them. If you expected a row, check that the ID is right and that the artist is attached to your account.
Retrying
| Situation | What to do |
|---|---|
invalid-jwt | Re-issue a token with login. Do not retry the same token. |
validation-failed | Fix the document or the header. Retrying unchanged will fail again. |
constraint-violation | Change the conflicting value — a different path, for instance. |
HTTP 5xx, or a resolver timeout | Retry with exponential backoff. Analytics fields are the most likely to be slow, since they call an external store. |
Writes are not idempotent. Before retrying a create_link that timed out, query for the domain + path to check whether it actually succeeded.