Skip to main content

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

StatuserrorMeaning
400ValidationErrorInvalid request parameters
402InsufficientCreditsErrorNot enough credits to complete the operation
403ForbiddenErrorMissing, unknown or mismatched credentials, or insufficient permissions
404ItemNotFoundErrorResource does not exist, or belongs to another tenant
409ConflictErrorRequest conflicts with the current resource state
422MissingWalletCredentialErrorThe key holder has no ETHEREUM wallet credential
note

The API does not use 401. Credential failures are 403.

Server errors

StatuserrorMeaning
500InternalErrorUnexpected 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, 409 and 422. These describe a problem with the request itself — retrying reproduces it. Fix the request, or the credentials, and call again.
  • 402 is 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 ERROR status carries an error_message explaining the cause.
  • Vaults and assets can be re-driven — see Retries.
  • Streams and data attachments cannot be retried; re-create them instead.

Next steps