Skip to main content

Error handling

Every method returns (result, error) where error is nil or a *ekyc.Error. Use errors.As to extract:

result, err := client.Liveness.Check(ctx, req)
if err != nil {
var ekycErr *ekyc.Error
if errors.As(err, &ekycErr) {
switch ekycErr.Code {
case ekyc.ErrCodeRateLimited:
time.Sleep(ekycErr.RetryAfter)
case ekyc.ErrCodeInvalidCredentials:
log.Fatal("API key revoked or wrong; check config")
}
}
return err
}

Error fields

type Error struct {
Code string // wire `error.type`
StatusCode int // HTTP status
Message string
RequestID string // surface in support tickets
Param string // for validation_failed
DocURL string // populated from `error.doc_url`
RetryAfter time.Duration // for rate_limited
// unexported `cause error` accessible via errors.Unwrap
}

Sentinel constants

ekyc.ErrCode* exposes the strings:

ekyc.ErrCodeTokenExpired
ekyc.ErrCodeInvalidToken
ekyc.ErrCodeInvalidCredentials
ekyc.ErrCodeRateLimited
ekyc.ErrCodeValidationFailed
ekyc.ErrCodePaymentRequired
ekyc.ErrCodePayloadTooLarge
ekyc.ErrCodeNotFound
ekyc.ErrCodeInternalError
ekyc.ErrCodeNetworkError

See Errors and retries for the full taxonomy.

Network errors

Transport-level failures (DNS, connection refused, timeout) surface as Code == ErrCodeNetworkError. The SDK retries them automatically (up to 3 attempts with exponential backoff) before returning. If you see network_error, you've already exhausted the retry budget.

var ekycErr *ekyc.Error
if errors.As(err, &ekycErr) && ekycErr.Code == ekyc.ErrCodeNetworkError {
if cause := errors.Unwrap(err); cause != nil {
log.Printf("network failure: %v", cause)
}
}

What 401 means in Go

The Go SDK does NOT auto-refresh on 401 (unlike Flutter). Reasons:

  • The dv_sk_* is your credential. If it's wrong, retrying with the same key won't help.
  • Your server controls the key lifecycle; the SDK has nothing to refresh against.

If you see 401 invalid_credentials, the right answer is "fix your config", not "retry".