diff --git a/docs/charts/README.md b/docs/charts/README.md
new file mode 100644
index 00000000000..f2598110661
--- /dev/null
+++ b/docs/charts/README.md
@@ -0,0 +1,7 @@
+# Charts and mermaid code
+
+The `mermaid` directory contains the [mermaid](https://mermaid-js.github.io/mermaid/#/) files which serve as the source code for the svg files included in the `../errors.md`
+
+To generate these files, there is an included script, `build_images.sh` which builds images for all the mermaid files in the `mermaid` directory.
+
+To use this script, the [mermaid cli](https://github.com/mermaid-js/mermaid-cli) must be installed and be accessible via your $PATH variable.
diff --git a/docs/charts/build_images.sh b/docs/charts/build_images.sh
new file mode 100755
index 00000000000..4a9a34f7dcf
--- /dev/null
+++ b/docs/charts/build_images.sh
@@ -0,0 +1,13 @@
+#! /bin/bash
+
+echo "Building svgs..."
+cd mermaid
+for f in *.mmd
+do
+ echo "Processing $f"
+ outname="${f%%.*}"
+ mmdc -i $f -o ../imgs/$outname.svg &
+done
+wait
+
+echo "Done"
diff --git a/docs/charts/imgs/MongoAPIError.svg b/docs/charts/imgs/MongoAPIError.svg
new file mode 100644
index 00000000000..9d46d069617
--- /dev/null
+++ b/docs/charts/imgs/MongoAPIError.svg
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/docs/charts/imgs/MongoError.svg b/docs/charts/imgs/MongoError.svg
new file mode 100644
index 00000000000..41f37b7adb0
--- /dev/null
+++ b/docs/charts/imgs/MongoError.svg
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/docs/charts/imgs/MongoRuntimeError_0.svg b/docs/charts/imgs/MongoRuntimeError_0.svg
new file mode 100644
index 00000000000..6a0961223a3
--- /dev/null
+++ b/docs/charts/imgs/MongoRuntimeError_0.svg
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/docs/charts/imgs/MongoRuntimeError_1.svg b/docs/charts/imgs/MongoRuntimeError_1.svg
new file mode 100644
index 00000000000..41dd25f7a6a
--- /dev/null
+++ b/docs/charts/imgs/MongoRuntimeError_1.svg
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/docs/charts/imgs/MongoRuntimeError_2.svg b/docs/charts/imgs/MongoRuntimeError_2.svg
new file mode 100644
index 00000000000..7d796039bcc
--- /dev/null
+++ b/docs/charts/imgs/MongoRuntimeError_2.svg
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/docs/charts/mermaid/MongoAPIError.mmd b/docs/charts/mermaid/MongoAPIError.mmd
new file mode 100644
index 00000000000..7275b04dc46
--- /dev/null
+++ b/docs/charts/mermaid/MongoAPIError.mmd
@@ -0,0 +1,5 @@
+graph TD
+ MongoAPIError --> MongoInvalidArgumentError
+ MongoAPIError --> MongoCompatibilityError
+ MongoAPIError --> MongoMissingCredentialsError
+ MongoAPIError --> MongoMissingDependencyError
diff --git a/docs/charts/mermaid/MongoError.mmd b/docs/charts/mermaid/MongoError.mmd
new file mode 100644
index 00000000000..5ed6b9fe5fb
--- /dev/null
+++ b/docs/charts/mermaid/MongoError.mmd
@@ -0,0 +1,8 @@
+graph TD
+ MongoError --> MongoDriverError
+ MongoError --> MongoNetworkError
+ MongoError --> MongoServerError
+ MongoError --> MongoSystemError
+ MongoDriverError --> MongoAPIError
+ MongoDriverError --> MongoRuntimeError
+
diff --git a/docs/charts/mermaid/MongoRuntimeError_0.mmd b/docs/charts/mermaid/MongoRuntimeError_0.mmd
new file mode 100644
index 00000000000..2646b76d906
--- /dev/null
+++ b/docs/charts/mermaid/MongoRuntimeError_0.mmd
@@ -0,0 +1,9 @@
+graph TD
+ MongoRuntimeError --> MongoBatchReExecutionError
+ MongoRuntimeError --> MongoCursorError
+ MongoRuntimeError --> MongoInvalidClassInstantiationError
+ MongoRuntimeError --> MongoNotConnectedError
+
+ MongoCursorError --> MongoTailableCursorError
+ MongoCursorError --> MongoCursorInUseError
+ MongoCursorError --> MongoCursorExhaustedError
diff --git a/docs/charts/mermaid/MongoRuntimeError_1.mmd b/docs/charts/mermaid/MongoRuntimeError_1.mmd
new file mode 100644
index 00000000000..7dfd97740ac
--- /dev/null
+++ b/docs/charts/mermaid/MongoRuntimeError_1.mmd
@@ -0,0 +1,10 @@
+graph TD
+ MongoRuntimeError --> MongoURIError
+ MongoRuntimeError --> MongoServerSelectionError
+ MongoRuntimeError --> MongoStreamError
+ MongoRuntimeError --> MongoCompressionError
+ MongoRuntimeError --> MongoDecompressionError
+
+ MongoStreamError --> MongoChangeStreamError
+ MongoStreamError --> MongoGridFSStreamError
+ MongoStreamError --> MongoGridFSChunkError
diff --git a/docs/charts/mermaid/MongoRuntimeError_2.mmd b/docs/charts/mermaid/MongoRuntimeError_2.mmd
new file mode 100644
index 00000000000..632d3326916
--- /dev/null
+++ b/docs/charts/mermaid/MongoRuntimeError_2.mmd
@@ -0,0 +1,9 @@
+graph TD
+ MongoRuntimeError --> MongoTransactionError
+ MongoRuntimeError --> MongoExpiredSessionError
+ MongoRuntimeError --> MongoKerberosError
+ MongoRuntimeError --> MongoResourceClosedError
+
+ MongoResourceClosedError --> MongoServerClosedError
+ MongoResourceClosedError --> MongoStreamClosedError
+ MongoResourceClosedError --> MongoTopologyClosedError
diff --git a/docs/errors.md b/docs/errors.md
new file mode 100644
index 00000000000..f008c365651
--- /dev/null
+++ b/docs/errors.md
@@ -0,0 +1,225 @@
+# Error Class Hierarchy
+
+**Title**: Error Class Hierarchy
+
+**Authors**: Warren James, Andy Mina
+
+**Advisory Group**: Daria Purdue, Eric Adum, Neal Beeken
+
+### Contents
+
+- [Introduction](#Introduction)
+- [Errors](#errors)
+ - [`MongoError`](#MongoError)
+ - [`MongoDriverError`](#MongoDriverError)
+ - [`MongoAPIError`](#MongoAPIError)
+ - [`MongoRuntimeError`](#MongoRuntimeError)
+ - [`MongoNetworkError`](#MongoNetworkError)
+ - [`MongoServerError`](#MongoServerError)
+ - [`MongoSystemError`](#MongoSystemError)
+- [Test Plan](#Test-Plan)
+ - [`MongoAPIError`](#MongoAPIError-1)
+ - [`MongoInvalidArgumentError`](#MongoInvalidArgumentError-1)
+ - [`MongoMissingCredentialsError`](#MongoMissingCredentialsError-1)
+ - [`MongoRuntimeError`](#MongoRuntimeError-1)
+ - [`MongoNotConnectedError`](#MongoNotConnectedError-1)
+ - [`MongoServerClosedError`](#MongoServerClosedError-1)
+ - [`MongoStreamClosedError`](#MongoStreamClosedError-1)
+ - [`MongoTopologyClosedError`](#MongoTopologyClosedError-1)
+ - [`MongoCursorExhaustedError`](#MongoCursorExhaustedError-1)
+ - [`MongoNetworkError`](#MongoNetworkError-1)
+ - [`MongoNetworkTimeoutError`](#MongoNetworkTimeoutError-1)
+
+# Errors
+
+All errors are derived from the `MongoError` class which should **never** be instantiated.
+There are four main error classes which stem from `MongoError`: `MongoDriverError`, `MongoNetworkError`, `MongoServerError`, and `MongoSystemError`.
+
+## `MongoError`
+
+The base class from which all errors in the Node driver subclass.
+`MongoError` should **never** be be directly instantiated.
+
+
+Children of `MongoError` include:
+
+- [`MongoDriverError`](#MongoDriverError)
+- [`MongoNetworkError`](#MongoNetworkError)
+- [`MongoServerError`](#MongoServerError)
+- [`MongoSystemError`](#MongoSystemError)
+
+## `MongoDriverError`
+
+This class represents errors which originate in the driver itself or in the user's use of the driver.
+This class should **never** be directly instantiated.
+Its children are the main classes of errors that most users will interact with: [**`MongoAPIError`**](#MongoAPIError) and [**`MongoRuntimeError`**](#MongoRuntimeError).
+
+### `MongoAPIError`
+
+This class represents errors which originate from misuse of the driver API and will generally be thrown before making contact with the server.
+This class should **never** be directly instantiated.
+
+Children of `MongoAPIError` include:
+
+- #### `MongoInvalidArgumentError`
+
+ - Thrown when the user supplies malformed, unexpected arguments or failed to provide a required argument or field.
+
+- #### `MongoCompatibilityError`
+
+ - Thrown when a feature that is not enabled or allowed for the current server configuration is used.
+
+- #### `MongoMissingCredentialsError`
+
+ - Thrown when a user fails to provide authentication credentials before attempting to connect to the mongo server.
+
+- #### `MongoMissingDependencyError`
+ - Thrown when a required module or dependency is not present.
+
+### `MongoRuntimeError`
+
+This class represents errors which occur when the driver encounters unexpected input or reaches an unexpected/invalid internal state.
+This class should **never** be directly instantiated.
+
+_MongoRuntimeError children (pt 1)_
+
+
+_MongoRuntimeError children (pt 2)_
+
+
+_MongoRuntimeError children (pt 3)_
+
+
+Children of `MongoRuntimeError` include:
+
+- #### `MongoTransactionError`
+
+ - Thrown when the user makes a mistake in the usage of transactions (e.g.: attempting to commit a transaction with a readPreference other than primary).
+
+- #### `MongoNotConnectedError`
+
+ - Thrown when the user attempts to operate on the data from a client that has not been connected to a MongoDB server instance.
+
+- #### `MongoKerberosError`
+
+ - Thrown when the user attempts to authenticate via Kerberos, but fails to connect to the Kerberos client.
+
+- #### `MongoCompressionError`
+
+ - Thrown when the driver fails to compress data before sending it to the server.
+
+- #### `MongoDecompressionError`
+
+ - Thrown when the driver fails to decompress data received from the server
+
+- #### `MongoExpiredSessionError`
+
+ - Thrown when the user attempts to operate on a session that has expired or has been closed.
+
+- #### `MongoURIError`
+
+ - Thrown when a user supplies an incorrect URI to the driver.
+
+- #### `MongoResourceClosedError`
+
+ - Thrown when there is an attempt to access a resource which has already been or will be closed/destroyed.
+ - Children of this error class include:
+ - **`MongoServerClosedError`**: Thrown when an attempt is made to operate on a closed server.
+ - **`MongoStreamClosedError`**: Thrown when an attempt is made to operate on a closed stream.
+ - **`MongoTopologyClosedError`**: Thrown when an attempt is made to operate on a dropped, or otherwise unavailable, database.
+
+- #### `MongoCursorError`
+
+ - Thrown when the user incorrectly uses a cursor object.
+ - Children of this error class include:
+ - **`MongoTailableCursorError`**: Thrown when the user calls a function or method that is not supported on a tailable cursor.
+ - **`MongoCursorInUseError`**: Thrown when the user attempts to add options to an already initialized cursor.
+ - **`MongoCursorExhaustedError`**: Thrown when an attempt is made to read from a cursor that has been exhausted.
+
+- #### `MongoStreamError`
+
+ - Thrown when a stream operation fails to execute.
+ - Children of this error class include:
+ - **`MongoChangeStreamError`**: Thrown when an error is encountered when operating on a ChangeStream.
+ - **`MongoGridFSStreamError`**: Thrown when an unexpected state is reached when operating on a GridFSStream.
+ - **`MongoGridFSChunkError`**: Thrown when a malformed or invalid chunk is encountered when reading from a GridFSStream.
+
+- #### `MongoBatchReExecutionError`
+
+ - Thrown when a user attempts to reexecute a batch command when one of the constituent commands has failed.
+
+- #### `MongoServerSelectionError`
+
+ - Thrown when the driver fails to select a server to complete an operation.
+
+## `MongoNetworkError`
+
+These are errors which prevent the driver from connecting to a mongo server instance. Children of this class include:
+
+- #### `MongoNetworkTimeoutError`
+
+ - Thrown when a timeout expires while attempting to connect to the mongo server
+
+## `MongoServerError`
+
+These are errors which wrap error responses received from the server.
+
+## `MongoSystemError`
+
+These are errors which originate from faulty environment setup.
+
+# Test Plan
+
+The test plan consists of a series of prose tests.
+As numerous errors are being introduced, select classes will be tested.
+The classes to be tested will be selected based on two characteristics:
+
+1. The **frequency** with which users may encounter this error. Errors that users will likely run into, including but not limited to `MongoInvalidArgumentError` and `MongoNetworkTimeoutError`, are a part of the test plan. _Note:_ Error classes that should never be instantiated, such as `MongoAPIError` and `MongoRuntimeError`, will not be tested as the user should not encounter them.
+2. The **scope** of the error. Errors that tackle a large subset of issues, including but not limited to `MongoServerError` and `MongoSystemError`, will _not_ be a part of the test plan.
+3. The **existing coverage** of the error. Errors that are already covered in existing tests will _not_ be a part of the test plan to avoid redundancy.
+
+## `MongoAPIError`
+
+#### `MongoInvalidArgumentError`
+
+- Create a `MongoClient` object and supply a number in place of the connection string when calling `.connect()`
+ - Assert that `MongoInvalidArgumentError` is thrown.
+
+#### `MongoMissingCredentialsError`
+
+- Fail to provide credentials when authenticating with the x509 mechanism.
+ - Assert that `MongoMissingCredentialsError` is thrown.
+
+## `MongoRuntimeError`
+
+#### `MongoNotConnectedError`
+
+- Attempt to access a database without establishing a connection to a MongoDB server.
+ - Assert that `MongoNotConnectedError` is thrown.
+
+#### `MongoServerClosedError`
+
+- Attempt to execute a query against a server that has closed.
+ - Assert that `MongoServerClosedError` is thrown.
+
+#### `MongoStreamClosedError`
+
+- Attempt to execute `tryNext()` on a `ChangeStream` object that is closed.
+ - Assert that `MongoStreamClosedError` is thrown.
+
+#### `MongoTopologyClosedError`
+
+- Attempt to execute `createCollection()` against a database that has been closed.
+ - Assert that `MongoTopologyClosedError` is thrown.
+
+#### `MongoCursorExhaustedError`
+
+- Attempt to continue reading a cursor after it has reached the end of the batch.
+ - Assert that `MongoCursorExhaustedError` is thrown.
+
+## `MongoNetworkError`
+
+#### `MongoNetworkTimeoutError`
+
+- Create a `MongoClient` object and set the `connectTimeoutMS` option to 1.
+ - Assert that a `MongoNetworkTimeoutError` is thrown.
diff --git a/test/functional/gridfs_stream.test.js b/test/functional/gridfs_stream.test.js
index ad96aa63620..e6f9a1f528c 100644
--- a/test/functional/gridfs_stream.test.js
+++ b/test/functional/gridfs_stream.test.js
@@ -95,6 +95,38 @@ describe('GridFS Stream', function () {
}
});
+ it('destroy publishes provided error', {
+ metadata: { requires: { topology: ['single'] } },
+ test: function (done) {
+ var configuration = this.configuration;
+
+ var client = configuration.newClient(configuration.writeConcernMax(), { maxPoolSize: 1 });
+
+ client.connect(function (err, client) {
+ var db = client.db(configuration.db);
+ db.dropDatabase(function (error) {
+ expect(error).to.not.exist;
+
+ var bucket = new GridFSBucket(db);
+ var readStream = fs.createReadStream('./LICENSE.md');
+ var uploadStream = bucket.openUploadStream('test.dat');
+ var errorMessage = 'error';
+
+ uploadStream.once('error', function (e) {
+ expect(e).to.equal(errorMessage);
+ client.close(done);
+ });
+
+ uploadStream.once('finish', function () {
+ uploadStream.destroy(errorMessage);
+ });
+
+ readStream.pipe(uploadStream);
+ });
+ });
+ }
+ });
+
/**
* Correctly stream a file from disk into GridFS using openUploadStream
*