onError method

  1. @override
void onError(
  1. DioException err,
  2. ErrorInterceptorHandler handler
)

Called when an exception was occurred during the request.

Implementation

@override
void onError(DioException err, ErrorInterceptorHandler handler) async {
  // Check if retry is enabled for this request
  final retryEnabled = err.requestOptions.extra['retry'] as bool? ?? config.enableRetry;

  if (!retryEnabled) {
    // Retry not enabled, pass error through
    return handler.next(err);
  }

  // Get retry count from request options or use global config
  final maxRetries = err.requestOptions.extra['retryCount'] as int? ?? config.retryCount;
  final currentRetry = err.requestOptions.extra['currentRetry'] as int? ?? 0;

  // Check if we should retry this error type
  if (!_shouldRetry(err) || currentRetry >= maxRetries) {
    logger.log(
      'Max retries reached or error not retryable. Giving up.',
      isError: true,
    );
    return handler.next(err);
  }

  // Calculate delay with exponential backoff if enabled
  final baseDelay = err.requestOptions.extra['retryDelay'] as Duration? ?? config.retryDelay;
  final useExponentialBackoff = err.requestOptions.extra['exponentialBackoff'] as bool? ??
      config.exponentialBackoff;

  final delay = useExponentialBackoff
      ? _calculateExponentialDelay(baseDelay, currentRetry)
      : baseDelay;

  // Log retry attempt
  logger.log(
    '🔄 Retrying request (${currentRetry + 1}/$maxRetries) after ${delay.inMilliseconds}ms...',
  );

  // Wait before retrying
  await Future.delayed(delay);

  // Create new options with updated retry count
  final newOptions = err.requestOptions.copyWith();
  newOptions.extra['currentRetry'] = currentRetry + 1;

  try {
    // Retry the request
    final response = await Dio().fetch(newOptions);
    return handler.resolve(response);
  } on DioException catch (e) {
    // If retry also fails, pass it to error handler again
    return super.onError(e, handler);
  }
}