SDK
Error handling
How the SDK surfaces failures, and how to react to them.
The SDK never throws on non-2xx responses — it returns { data, error } so
you can branch explicitly.
const { data, error } = await aden.api.v1.tracks({ id: 42 }).get()
if (error) {
// error.status is the HTTP status code (number)
// error.value is the parsed JSON body from the server
switch (error.status) {
case 401:
// Token missing or invalid — prompt re-auth
break
case 403:
// Auth succeeded but scope is insufficient
break
case 404:
// Track doesn't exist or isn't visible to this key
break
case 429:
// Rate-limited — back off and retry
break
default:
throw new Error(`Unexpected: ${error.status}`)
}
return
}
use(data)Shape of errors
All error bodies follow:
{ "error": "Unauthorized" }The global error handler in packages/api/src/index.ts maps unknown errors
to 500 { error: <message> } and auth failures to 401 { error: "Unauthorized" }.
Network errors
If the request never reaches the server, error is populated with
status: 'FETCH_ERROR' and value is the underlying Error. This is a
good place to retry or flip your app to "offline":
const { data, error } = await aden.api.v1.tracks.get()
if (error?.status === 'FETCH_ERROR') {
showOfflineBanner()
return
}Rate limits
429 responses include standard rate-limit headers:
X-RateLimit-Limit— maximum requests in the window.X-RateLimit-Remaining— how many you have left.X-RateLimit-Reset— unix epoch (seconds) when the window resets.
A simple retry helper:
async function withBackoff<T>(
fn: () => Promise<{ data: T | null; error: unknown }>,
attempts = 3
) {
for (let i = 0; i < attempts; i++) {
const result = await fn()
const err = result.error as { status?: number } | null
if (err?.status !== 429) return result
await new Promise((r) => setTimeout(r, 2 ** i * 1000))
}
throw new Error('Exhausted retries')
}