Error Handling
Every Filedgr API error returns the same flat JSON object:
{
"error": "ItemNotFoundError",
"message": "Oops! Vault 3fa85f64-5717-4562-b3fc-2c963f66afa6 not found"
}
error is a string, not a nested object. There is no error code, request id, timestamp or
details array — do not write client code that reads them.
Status codes
Client errors
| Status | error | Meaning |
|---|---|---|
400 | ValidationError | Invalid request parameters |
402 | InsufficientCreditsError | Not enough credits to complete the operation |
403 | ForbiddenError | Missing, unknown or mismatched credentials, or insufficient permissions |
404 | ItemNotFoundError | Resource does not exist, or belongs to another tenant |
409 | ConflictError | Request conflicts with the current resource state |
422 | MissingWalletCredentialError | The key holder has no ETHEREUM wallet credential |
The API does not use 401. Credential failures are 403.
Server errors
| Status | error | Meaning |
|---|---|---|
500 | InternalError | Unexpected server condition |
Two exceptions to the standard shape
Schema validation failures come from the framework and use a detail array instead:
{ "detail": [{ "loc": ["body", "template_id"], "msg": "Input should be a valid UUID" }] }
Authentication failures also use detail:
{ "detail": "Could not validate API KEY" }
Insufficient credits
A 402 carries three extra fields beyond the standard shape, so you can tell the difference
between "top up" and "subscribe":
{
"error": "InsufficientCreditsError",
"message": "Not enough credits",
"required": 10.0,
"balance": 2.5,
"has_subscription": true
}
Creating a vault, stream or data attachment runs a credit pre-flight check, so you get this immediately rather than watching the resource fail asynchronously. See Credits & Billing.
Handling errors in your client
async function filedgrRequest(path, options = {}) {
const res = await fetch(`https://api.filedgr.network${path}`, {
...options,
headers: {
'x-api-key': process.env.FILEDGR_API_KEY,
'x-api-secret': process.env.FILEDGR_API_SECRET,
'Content-Type': 'application/json',
...options.headers,
},
});
// Empty list responses carry no body at all.
if (res.status === 204) return null;
if (!res.ok) {
const body = await res.json().catch(() => ({}));
// Schema and auth failures use `detail`; everything else uses `error`/`message`.
const name = body.error ?? 'RequestFailed';
const detail = body.message ?? JSON.stringify(body.detail ?? {});
const err = new Error(`${name}: ${detail}`);
err.status = res.status;
err.body = body;
throw err;
}
return res.json();
}
What to retry
- Retryable:
5xx, timeouts and connection errors. Use exponential backoff with jitter. - Not retryable:
400,403,404,409and422. These describe a problem with the request itself — retrying reproduces it. Fix the request, or the credentials, and call again. 402is retryable only once credits have been added.
Honour Retry-After whenever it is present on a response.
Asynchronous failures
Vault, stream and attachment creation are asynchronous, so a 2xx means accepted, not
finished. Poll the resource and watch status:
- A terminal
ERRORstatus carries anerror_messageexplaining the cause. - Vaults and assets can be re-driven — see Retries.
- Streams and data attachments cannot be retried; re-create them instead.
Next steps
- Conventions — pagination, the 204-on-empty rule, ledger values
- Rate Limits
- Full API reference