Repository navigation
Error Handling and Reliability
Every service method returns an error that can be classified with the standard library's errors.As and errors.Is. The client distinguishes invalid configuration, missing Pro credentials, non-success HTTP responses, rate limits, network failures, and JSON decode failures. URLs stored in these errors are redacted when a Pro key is involved.1
| Type | When it occurs | Useful fields |
|---|---|---|
*ConfigError |
New receives invalid configuration. |
Msg |
*ProAPIKeyRequiredError |
A Pro method is called without WithAPIKey. No request is built. |
Route |
*NotFoundError |
The API returns HTTP 404. |
Embedded *APIError
|
*RateLimitError |
The API returns HTTP 429. |
RetryAfter, embedded *APIError
|
*APIError |
The API returns another non-2xx response. |
StatusCode, URL, Header, Body
|
*TransportError |
Network, DNS, TLS, timeout, or cancellation failure. |
URL, Err; it unwraps to the underlying cause. |
*DecodeError |
A successful response is not one complete valid JSON value. |
URL, Err; it unwraps to the decode error. |
APIError.Body is limited to 4096 bytes. The library also redacts the configured Pro key from error URLs, headers, bodies, and nested standard-library URL errors before returning them.1
Handle the situations that have different recovery actions before returning a general error.
_, err := client.TVL().GetProtocol(ctx, "not-a-real-protocol")
var (
notFound *defillama.NotFoundError
rateLimit *defillama.RateLimitError
apiErr *defillama.APIError
transport *defillama.TransportError
decode *defillama.DecodeError
missingKey *defillama.ProAPIKeyRequiredError
)
switch {
case errors.As(err, ¬Found):
// The resource does not exist.
case errors.As(err, &rateLimit):
// RetryAfter is zero when the server supplied no usable Retry-After value.
return fmt.Errorf("rate-limited; retry after %s: %w", rateLimit.RetryAfter, err)
case errors.As(err, &apiErr):
// Another HTTP error: inspect StatusCode, Header, and Body.
case errors.As(err, &transport):
// errors.Is/As can reach the root cause through TransportError.
case errors.As(err, &decode):
// The upstream success body was not valid JSON.
case errors.As(err, &missingKey):
// Configure the client with WithAPIKey before this call.
case err != nil:
return err
}Keep an appropriate context deadline even where retry is enabled. If a context is cancelled or reaches its deadline while waiting to retry, the client returns promptly.2
Retries are disabled by default. Set MaxAttempts greater than one to retry eligible GET failures:
client, err := defillama.New(defillama.WithRetryPolicy(defillama.RetryPolicy{
MaxAttempts: 3,
BaseDelay: 250 * time.Millisecond,
MaxDelay: 2 * time.Second,
Jitter: true,
}))Only the following errors are retryable: transient transport errors, *RateLimitError for HTTP 429, and *APIError with a 5xx status. The client does not retry cancellation, ordinary 4xx responses, permanent transport errors, or DecodeError. Its backoff doubles from BaseDelay, is capped by MaxDelay, may include ±50% jitter, and waits at least as long as a valid server Retry-After when necessary.2
MaxAttempts counts the initial request. Therefore MaxAttempts: 1 means no retry.
The Client has immutable configuration after construction, holds no request-level state, and is safe to share across goroutines. Create it once for a given configuration and use a context suitable for each call.
client, err := defillama.New(defillama.WithTimeout(10 * time.Second))
if err != nil {
return err
}
ctx, cancel := context.WithTimeout(parentCtx, 5*time.Second)
defer cancel()
prices, err := client.Prices().GetCurrentPrices(ctx, []string{"coingecko:bitcoin"})WithTimeout configures only the SDK-created HTTP client. If the application injects a client with WithHTTPClient, it owns that client's timeout and transport settings. The request context can always impose a tighter deadline.3
Use one client per configuration, a bounded context per request, and an explicit retry policy only where retries fit the calling workload. Branch on NotFoundError and RateLimitError rather than parsing error strings. Never log the raw API-key source, even though returned SDK errors redact the key. Convert float64 financial transport values before calculations that require exact decimal semantics.
defillama-go is an MIT-licensed Go client for the DefiLlama API. For endpoint semantics and API-plan details, consult the official DefiLlama API reference.