Skip to main content
Every failed request returns the same JSON shape with a stable code. Use this page to decide what your code does with each one.

The error shape

A path under /api that is not an endpoint returns the same shape with 404 not_found, so your client never has to parse an HTML error page. The SDKs raise this as an exception: YungleApiError in JavaScript and YungleError in Python, each with status, code, details and retryable.

Error codes

CodeStatusWhat to do
unauthorized401Check the key. Missing, malformed, unknown, revoked and expired all look the same on purpose.
upgrade_required402The workspace is on the free plan. Nothing to retry.
out_of_credit402API uploads past the monthly allowance are paid from prepaid credit, and there is none left. Top up in the dashboard, then retry.
insufficient_scope403The key lacks a scope. details.required names it; create a key that has it.
not_found404No such resource, or it belongs to another workspace — deliberately the same answer. Also returned for a path that is not an endpoint.
invalid_request400Bad body. details.issues lists field paths and reasons.
folder_error400Duplicate or invalid folder name, or too deep. details.code says which.
conflict409Already exists — a contact with that email, typically. Usually safe to skip. With details.reason set, it is about your Idempotency-Key instead; see below.
not_editable410The transfer has been sent, revoked or expired. Composing is over.
quota_exceeded413Storage is full. details carries used and total bytes. Delete something.
transfer_too_large413One transfer exceeded the plan ceiling. details.limitBytes is the cap.
rate_limited429Back off. Honour the Retry-After header, or throttle on the RateLimit header before you get here.
email_budget_exhausted429Daily outbound email or invite budget spent. Nothing was sent and nothing changed. For a transfer, finalize again without recipients to get the link now, or retry tomorrow.
password_required403The shared link is password protected. Send password with the request.
wrong_password403Wrong password for the shared link. Attempts are budgeted per workspace and per link; after too many you get rate_limited.
guests_only403The collection is open to invited guests only. A guest opens it in a browser, signed in; the link alone is not enough.
e2ee_unsupported409End-to-end encrypted. Yungle holds only ciphertext and never the key, so it cannot give you usable bytes — open the full link, # part included, in a browser.
internal_error500Ours. details.requestId ties it to our logs — quote it if you get in touch.

How to handle each class

Not found is never forbidden

A resource that exists but belongs to another workspace returns 404, not 403. A 403 would confirm the id is real and let anyone probe for other workspaces’ ids. You cannot tell the two cases apart, and that is intended.

Retrying

Retry only these:
  • 429: after the number of seconds in the Retry-After header. Most 429 bodies also carry details.retryAfterSeconds.
  • 500 and dropped connections: with exponential backoff, a few times.
  • 409 with details.reason idempotency_in_progress: after Retry-After, to get the first request’s result.
Every other 4xx is deterministic: the same request fails the same way. Before you retry a POST, make it safe to repeat by sending an Idempotency-Key. Pagination and idempotency explains how. The SDKs already retry 429 and 5xx responses, and send an Idempotency-Key on every POST.

Next steps

Pagination and idempotency

Walk long lists and make retries safe.

Limits

The limits behind 429, 413 and email_budget_exhausted.