Errors
The error format, every HTTP status the mallow API returns, the error codes it sets, and which failures are safe to retry.
The Error Format
A failed request returns a JSON body with one error object:
{ "error": { "message": "Invalid API key" } }| Field | Present | Use |
|---|---|---|
error.message | Always | Text for a log or a person. The wording can change |
error.code | Sometimes | A stable name for the failure. See Error codes |
These are real responses, captured on 12 October 2026 from requests sent without a valid key:
curl -i https://api.mallow.art/v1/artworks/trending
# HTTP/2 401
# {"error":{"message":"Invalid API key"}}
curl -i https://api.mallow.art/v2/auctions/So11111111111111111111111111111111111111112
# HTTP/2 401
# {"error":{"message":"Unauthorized"}}Most errors carry no code
Only some /v1 errors set code. No /v2 error does. Decide on the HTTP status first,
then on code when there's one, and never rely on code being present.
Some /v1 errors add fields:
- A validation error adds
error.details, the full list of problems. SeeVALIDATION_ERROR - Some errors add an
infoobject besideerror, with the values the request was about
Responses Without the Format
A few failures are returned before the request reaches mallow's handlers, and their body isn't JSON. Read the body as text before you parse it.
| Status | When | Body |
|---|---|---|
400 | The body of a /v2 POST isn't valid JSON | Plain text |
415 | A /v2 POST without content-type: application/json | Plain text |
422 | The body of a /v2 POST is missing a required field, or a field has the wrong type | Plain text naming the field |
408 | A /v2 request ran longer than 15 seconds | Empty |
404 | A /v2 path that doesn't exist | Empty |
HTTP Statuses
| Status | Meaning | What to do |
|---|---|---|
400 | The request isn't valid, or what it asks for can't be done right now. Examples from /v2: Listing not found on a buy, Auction has not yet ended on a settle, User is not allowlisted on a bid | Read message. Fix the request or read the current state again. Sending the same request again returns the same error |
401 | The key is missing or not valid. /v1 returns Invalid API key in both cases. /v2 returns Unauthorized when no key was sent and Invalid API key when the key isn't recognised | Check the x-api-key header. See Authentication |
404 | The thing the request names doesn't exist. See 404 | Stop, or read the state again |
408 | A /v2 request timed out after 15 seconds | Retry |
409 | A Magic Eden order changed after you got a quote. See 409 | Get a new quote |
415, 422 | A /v2 request body was rejected. See Responses without the format. Bid or buy also returns 422 when the wallet has reached the listing's buy limit | Fix the request |
429 | Over the rate limit | Wait for the window to end. See Rate limits and retries |
500 | Something failed on mallow's side. On /v2 the message is always Internal server error. On /v1 it can name the cause | Retry a read or a build after a pause. If it keeps failing, tell us |
503 | A dependency wasn't available. The draw builders return this when chain state couldn't be read or the draw couldn't be simulated. The Magic Eden routes return it when they're busy or switched off | Retry after a pause |
The reference pages list 400, 401, 404, 409, 429 and 500. The API also returns
the other statuses in this table.
404
| Operations | A 404 means |
|---|---|
| Artwork by mint, Public profile by address | mallow has no artwork or user for that address. code is NOT_FOUND |
| The five account reads | The address holds an account of another type or another program. An address with no account at all is a 200 with account: null |
| Edition buyer stats | The mint has no listing |
| Raffle buyer stats, Buy raffle tickets, Claim raffle prize | The raffle doesn't exist |
| Cancel offer | The buyer has no offer on that artwork |
| Bid or buy | The artwork has no listing or auction, or mallow hasn't indexed it |
| Schedule a bid | The artwork has no auction |
| Draw a Gumball, Draw a Jellybean | The machine doesn't exist |
The other /v2 builders return a 400 for a missing listing, auction, offer or raffle,
not a 404.
409
Only Buy on Magic Eden returns 409. The order's
price, currency, expiry or escrow changed after the quote, or the total passed the limits
you sent. The message starts with STALE_ORDER:. Request the
quote again and show the buyer the new terms.
Error Codes
These are all the codes the public API sets. All four come from /v1.
| Code | Status | Returned by | Meaning | What to do |
|---|---|---|---|---|
VALIDATION_ERROR | 400 | Every /v1 POST | The request body failed validation | Fix the request. message names the first problem and details lists them all |
NOT_FOUND | 404 | Artwork by mint, Public profile by address | No artwork or user for that address | Stop. Check the address |
RATE_LIMITED | 429 | Every /v1 operation | The key is over its limit for this minute | Wait, then retry. A /v2 429 has the same message and no code |
INTERNAL_ERROR | 500 | The /v1 artwork, event, reward and profile reads, except Trending artworks | An unexpected failure. message can name the cause | Retry after a pause |
Every other error has no code, including every 401.
A validation error has this shape. The values are placeholders:
{
"error": {
"message": "<field>: <problem>",
"code": "VALIDATION_ERROR",
"details": [
{
"location": "body",
"issues": [{ "path": "<field>", "message": "<problem>" }]
}
]
}
}Failures Inside a 200
Two groups of operations report a failure in a successful response. Check the body, not only the status.
- Draw submit and draw status. Send signed gumball draws, Gumball draw status and the Jellybean versions return one result per transaction. A refused or failed draw has an
errorwith amessage. See Draws go through mallow - Magic Eden quote. Magic Eden buy quote returns
available: falsewith areasonwhen the order can't be bought
A state read that finds nothing is also a 200, with null in place of the state.
Treat that as a valid answer.
What Is Safe to Retry
| Call | Safe to repeat | Notes |
|---|---|---|
| Any read | Yes | |
Any builder: /v2/tx/*, Bid or buy, the scheduled-bid builders, the draw builders | Yes | A build changes nothing on chain |
| Draw status | Yes | |
| Draw submit | No | Each draw transaction is accepted once. A repeat returns an error for that transaction and no new information |
| Sending the same signed transaction to your RPC | Yes | The network accepts a signature once |
| Building again and sending the new transaction | Only after the first one expired | If the first transaction landed, the second is a second purchase. Look up the first signature before you rebuild |
Retry 408, 429, 500 and 503. Don't retry any other 4xx without changing the
request. The quickstart has a retry helper.
On-Chain Failures
The API builds transactions and you run them. A transaction can build without error and still fail when you send it, and that failure comes back from your Solana RPC rather than from mallow.
It shows up in one of two places:
- At send time. The RPC simulates the transaction first and rejects it, with the program logs in the error
- After it lands. The signature's status carries an
err, whichconfirmTransactionreturns invalue.err
Either way the error names the instruction that failed and a number:
{ "InstructionError": [2, { "Custom": 6002 }] }Here 2 is the position of the instruction in the transaction, and 6002 is the error
code of the program that instruction calls. The same number means different things in
different programs, so find the program first. Its address is in the decoded transaction
and in the logs. SDKs and programs lists mallow's.
mallow's programs number their own errors from 6000. Where to look a code up:
| Program | Error list |
|---|---|
| Market, Auction, Rewards | The npm clients export every code and a lookup: getMallowMarketErrorMessage, getMallowAuctionErrorMessage, getMallowRewardsErrorMessage. See SDKs and programs |
| Sweepstake | getMallowSweepstakeErrorMessage from @mallow-labs/mallow-sweepstake-sdk/generated |
| Gumball | errors.rs |
| Gumball Guard | errors.rs |
| Jellybean | errors.rs |
Common causes are a listing that sold or was cancelled between the build and the send, a wallet without enough funds for the price and fees, and an expired blockhash. For the last one, see Blockhash expiry.
Draws are the exception, because mallow sends them. A draw that fails simulation comes
back from the submit call with an error and its logs. A draw that fails on chain shows
up in the status call.