diff --git a/lib/minio.dart b/lib/minio.dart
index 087f4a5435cd5d8f241b6f51e05aa3a05cbc7944..113198ef31fe5e9a2a581dcb2ec1d5b10ac4f3a7 100644
--- a/lib/minio.dart
+++ b/lib/minio.dart
@@ -1,8 +1,6 @@
-/// Support for doing something awesome.
-///
-/// More dartdocs go here.
 library minio;
 
 export 'src/minio.dart';
+export 'src/minio_errors.dart';
 
 // TODO: Export any libraries intended for clients of this package.
diff --git a/lib/src/minio.dart b/lib/src/minio.dart
index 1545b58f1de6b0d27d9bab13be548b164800205a..670ddb1a80aedff180714172c79a6b3090a7c435 100644
--- a/lib/src/minio.dart
+++ b/lib/src/minio.dart
@@ -67,16 +67,34 @@ class Minio {
   final _regionMap = <String, String>{};
 
   /// Checks if a bucket exists.
+  ///
+  /// Returns `true` only if the [bucket] exists and you have the permission
+  /// to access it. Returns `false` if the [bucket] does not exist or you
+  /// don't have the permission to access it.
   Future<bool> bucketExists(String bucket) async {
     MinioInvalidBucketNameError.check(bucket);
     try {
-      await _client.request(method: 'HEAD', bucket: bucket);
+      final response = await _client.request(method: 'HEAD', bucket: bucket);
+      validate(response);
+      return response.statusCode == 200;
     } on MinioS3Error catch (e) {
       final code = e.error.code;
-      if (code == 'NoSuchBucket' || code == 'NotFound') return false;
+      if (code == 'NoSuchBucket' || code == 'NotFound' || code == 'Not Found') {
+        return false;
+      }
+      rethrow;
+    } on StateError catch (e) {
+      // Insight from testing: in most cases, AWS S3 returns the HTTP status code
+      // 404 when a bucket does not exist. Whereas in other cases, when the bucket
+      // does not exist, S3 returns the HTTP status code 301 Redirect instead of
+      // status code 404 as officially documented. Then, this redirect response
+      // lacks the HTTP header `location` which causes this exception in Dart's
+      // HTTP library (`http_impl.dart`).
+      if (e.message == 'Response has no Location header for redirect') {
+        return false;
+      }
       rethrow;
     }
-    return true;
   }
 
   int _calculatePartSize(int size) {
@@ -441,6 +459,7 @@ class Minio {
       method: 'GET',
       region: region ?? 'us-east-1',
     );
+    validate(resp);
     final bucketsNode =
         xml.XmlDocument.parse(resp.body).findAllElements('Buckets').first;
     return bucketsNode.children.map((n) => Bucket.fromXml(n)).toList();
diff --git a/lib/src/minio_helpers.dart b/lib/src/minio_helpers.dart
index b8d2e381b4993c16fd4936aef317a1b9fd49aa47..4cd2fdc13e97ece4aabecf0e65aacda27eae296d 100644
--- a/lib/src/minio_helpers.dart
+++ b/lib/src/minio_helpers.dart
@@ -217,9 +217,17 @@ Future<void> validateStreamed(
 
 void validate(Response response, {int expect}) {
   if (response.statusCode >= 400) {
-    final body = xml.XmlDocument.parse(response.body);
-    final error = Error.fromXml(body.rootElement);
-    throw MinioS3Error(error.message, error, response);
+    var error;
+
+    // Parse HTTP response body as XML only when not empty
+    if (response.body == null || response.body.isEmpty) {
+      error = Error(response.reasonPhrase, null, response.reasonPhrase, null);
+    } else {
+      final body = xml.XmlDocument.parse(response.body);
+      error = Error.fromXml(body.rootElement);
+    }
+
+    throw MinioS3Error(error?.message, error, response);
   }
 
   if (expect != null && response.statusCode != expect) {
diff --git a/test/minio_dart_test.dart b/test/minio_dart_test.dart
index f6775d5abcf6a772254b007b6870b59be68f6721..e8626bcee58a4aaa0effa6be67cd70482564e658 100644
--- a/test/minio_dart_test.dart
+++ b/test/minio_dart_test.dart
@@ -1,14 +1,119 @@
+import 'package:minio/minio.dart';
+import 'package:test/test.dart';
 
 void main() {
-  // group('A group of tests', () {
-  //   Awesome awesome;
+  group('listBuckets', () {
+    test('listBuckets() succeeds', () async {
+      final minio = _getClient();
 
-  //   setUp(() {
-  //     awesome = Awesome();
-  //   });
+      expect(() async => await minio.listBuckets(), returnsNormally);
+    });
 
-  //   test('First Test', () {
-  //     expect(awesome.isAwesome, isTrue);
-  //   });
-  // });
+    test('listBuckets() fails due to wrong access key', () async {
+      final minio = _getClient(accessKey: 'incorrect-access-key');
+
+      expect(
+        () async => await minio.listBuckets(),
+        throwsA(
+          isA<MinioError>().having(
+            (e) => e.message,
+            'message',
+            'The Access Key Id you provided does not exist in our records.',
+          ),
+        ),
+      );
+    });
+
+    test('listBuckets() fails due to wrong secret key', () async {
+      final minio = _getClient(secretKey: 'incorrect-secret-key');
+
+      expect(
+        () async => await minio.listBuckets(),
+        throwsA(
+          isA<MinioError>().having(
+            (e) => e.message,
+            'message',
+            'The request signature we calculated does not match the signature you provided. Check your key and signing method.',
+          ),
+        ),
+      );
+    });
+  });
+
+  group('bucketExists', () {
+    final bucketName = DateTime.now().millisecondsSinceEpoch.toString();
+
+    setUpAll(() async {
+      final minio = _getClient();
+      await minio.makeBucket(bucketName);
+    });
+
+    tearDownAll(() async {
+      final minio = _getClient();
+      await minio.removeBucket(bucketName);
+    });
+
+    test('bucketExists() returns true for an existing bucket', () async {
+      final minio = _getClient();
+      expect(await minio.bucketExists(bucketName), equals(true));
+    });
+
+    test('bucketExists() returns false for a non-existent bucket', () async {
+      final minio = _getClient();
+      expect(await minio.bucketExists('non-existing-bucket-name'), equals(false));
+    });
+
+    test('bucketExists() fails due to wrong access key', () async {
+      final minio = _getClient(accessKey: 'incorrect-access-key');
+      expect(
+        () async => await minio.bucketExists(bucketName),
+        throwsA(
+          isA<MinioError>().having(
+            (e) => e.message,
+            'message',
+            'Forbidden',
+          ),
+        ),
+      );
+    });
+
+    test('bucketExists() fails due to wrong secret key', () async {
+      final minio = _getClient(secretKey: 'incorrect-secret-key');
+      expect(
+        () async => await minio.bucketExists(bucketName),
+        throwsA(
+          isA<MinioError>().having(
+            (e) => e.message,
+            'message',
+            'Forbidden',
+          ),
+        ),
+      );
+    });
+  });
 }
+
+/// Initializes an instance of [Minio] with per default valid configuration.
+///
+/// Don't worry, these credentials for MinIO are publicly available and
+/// connect only to the MinIO demo server at `play.minio.io`.
+Minio _getClient({
+  String endpoint = 'play.minio.io',
+  int port = 443,
+  bool useSSL = true,
+  String accessKey = 'Q3AM3UQ867SPQQA43P2F',
+  String secretKey = 'zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG',
+  String sessionToken = '',
+  String region = 'us-east-1',
+  bool enableTrace = false,
+}) =>
+    Minio(
+      endPoint: endpoint,
+      port: port,
+      useSSL: useSSL,
+      accessKey: accessKey,
+      secretKey: secretKey,
+      sessionToken: sessionToken,
+      region: region,
+      enableTrace: enableTrace,
+    );