diff --git a/doc/api/errors.markdown b/doc/api/errors.markdown index 505241fc89..5e5f9acb99 100644 --- a/doc/api/errors.markdown +++ b/doc/api/errors.markdown @@ -18,6 +18,123 @@ The style of API called determines how generated errors are handed back, or the error. Exceptions can be intercepted using the `try / catch` construct; other propagation strategies are covered [below](#errors_error_propagation_and_interception). +## Error Propagation and Interception + + + +All Node.js APIs will treat invalid arguments as exceptional -- that is, if passed +invalid arguments, they will *immediately* generate and throw the error as an +exception, even if they are an otherwise asynchronous API. + +Synchronous APIs (like +[fs.readFileSync](fs.html#fs_fs_readfilesync_filename_options)) will throw the +error. The act of *throwing* a value (in this case, the error) turns the value +into an **exception**. Exceptions may be caught using the `try { } catch(err) +{ }` construct. + +Asynchronous APIs have **two** mechanisms for error propagation; one mechanism +for APIs that represent a single operation, and one for APIs that represent +multiple operations over time. + +### Error events + + + +The other mechanism for providing errors is the "error" event. This is +typically used by [stream-based](stream.html) and [event emitter-based](events.html#events_class_events_eventemitter) APIs, which +themselves represent a series of asynchronous operations over time (versus a +single operation that may pass or fail). If no "error" event handler is +attached to the source of the error, the error will be thrown. At this point, +it will crash the process as an unhandled exception unless [domains](domain.html) are +employed appropriately or [process.on('uncaughtException')](process.html#process_event_uncaughtexception) has a handler. + +```javascript +var net = require('net'); + +var connection = net.connect('localhost'); + +// adding an "error" event handler to a stream: +connection.on('error', function(err) { + // if the connection is reset by the server, or if it can't + // connect at all, or on any sort of error encountered by + // the connection, the error will be sent here. + console.error(err); +}); + +connection.pipe(process.stdout); +``` + +The "throw when no error handlers are attached behavior" is not limited to APIs +provided by Node.js -- even user created event emitters and streams will throw +errors when no error handlers are attached. An example: + +```javascript +var EventEmitter = require('events'); + +var ee = new EventEmitter(); + +setImmediate(function() { + // this will crash the process because no "error" event + // handler has been added. + ee.emit('error', new Error('This will crash')); +}); +``` + +As with node style callbacks, errors generated this way *cannot* be intercepted +by `try { } catch(err) { }` -- they happen *after* the calling code has already +exited. + +### Node style callbacks + + + +Single operation APIs take "node style callbacks" -- a +function provided to the API as an argument. The node style callback takes +at least **one** argument -- `error` -- that will either be `null` (if no error +was encountered) or an `Error` instance. For instance: + +```javascript +var fs = require('fs'); + +fs.readFile('/some/file/that/does-not-exist', function nodeStyleCallback(err, data) { + console.log(err) // Error: ENOENT + console.log(data) // undefined / null +}); + +fs.readFile('/some/file/that/does-exist', function(err, data) { + console.log(err) // null + console.log(data) // +}) +``` + +Note that `try { } catch(err) { }` **cannot** intercept errors generated by +asynchronous APIs. A common mistake for beginners is to try to use `throw` +inside their node style callback: + +```javascript +// THIS WILL NOT WORK: +var fs = require('fs'); + +try { + fs.readFile('/some/file/that/does-not-exist', function(err, data) { + // mistaken assumption: throwing here... + if (err) { + throw err; + } + }); +} catch(err) { + // ... will be caught here -- this is incorrect! + console.log(err); // Error: ENOENT +} +``` + +This will not work! By the time the node style callback has been called, the +surrounding code (including the `try { } catch(err) { }` will have already +exited. Throwing an error inside a node style callback **will crash the process** in most cases. +If [domains](domain.html) are enabled, they may intercept the thrown error; similarly, if a +handler has been added to `process.on('uncaughtException')`, it will intercept +the error. + ## JavaScript Errors @@ -45,6 +162,54 @@ was called. Stack traces are subject to [V8's stack trace API](https://code.goog Stack traces only extend to the beginning of synchronous code execution, *or* a number of frames given by `Error.stackTraceLimit`, whichever is smaller. +#### Error.captureStackTrace(targetObject[, constructorOpt]) + +Creates a `.stack` property on `targetObject`, which when accessed returns +a string representing the location in the program at which `Error.captureStackTrace` +was called. + +```javascript +var myObject = {}; + +Error.captureStackTrace(myObject); + +myObject.stack // similar to `new Error().stack` +``` + +The first line of the trace, instead of being prefixed with `ErrorType: +message`, will be the result of `targetObject.toString()`. + +`constructorOpt` optionally accepts a function. If given, all frames above +`constructorOpt`, including `constructorOpt`, will be omitted from the generated +stack trace. + +This is useful for hiding implementation details of error generation from the +end user. A common way of using this parameter is to pass the current Error +constructor to it: + +```javascript + +function MyError() { + Error.captureStackTrace(this, MyError); +} + +// without passing MyError to captureStackTrace, the MyError +// frame would should up in the .stack property. by passing +// the constructor, we omit that frame and all frames above it. +new MyError().stack + +``` + +#### Error.stackTraceLimit + +Property that determines the number of stack frames collected by a stack trace +(whether generated by `new Error().stack` or `Error.captureStackTrace(obj)`). + +The initial value is `10`. It may be set to any valid JavaScript number, which +will affect any stack trace captured *after* the value has been changed. If set +to a non-number value, stack traces will not capture any frames and will report +`undefined` on access. + #### error.message A string of the value passed to `Error()` upon instantiation. The message will @@ -119,54 +284,6 @@ loop tick. System-level errors are generated as augmented Error instances, which are detailed [below](#errors_system_errors). -#### Error.captureStackTrace(targetObject[, constructorOpt]) - -Creates a `.stack` property on `targetObject`, which when accessed returns -a string representing the location in the program at which `Error.captureStackTrace` -was called. - -```javascript -var myObject = {}; - -Error.captureStackTrace(myObject); - -myObject.stack // similar to `new Error().stack` -``` - -The first line of the trace, instead of being prefixed with `ErrorType: -message`, will be the result of `targetObject.toString()`. - -`constructorOpt` optionally accepts a function. If given, all frames above -`constructorOpt`, including `constructorOpt`, will be omitted from the generated -stack trace. - -This is useful for hiding implementation details of error generation from the -end user. A common way of using this parameter is to pass the current Error -constructor to it: - -```javascript - -function MyError() { - Error.captureStackTrace(this, MyError); -} - -// without passing MyError to captureStackTrace, the MyError -// frame would should up in the .stack property. by passing -// the constructor, we omit that frame and all frames above it. -new MyError().stack - -``` - -#### Error.stackTraceLimit - -Property that determines the number of stack frames collected by a stack trace -(whether generated by `new Error().stack` or `Error.captureStackTrace(obj)`). - -The initial value is `10`. It may be set to any valid JavaScript number, which -will affect any stack trace captured *after* the value has been changed. If set -to a non-number value, stack traces will not capture any frames and will report -`undefined` on access. - ### Class: RangeError A subclass of Error that indicates that a provided argument was not within the @@ -180,19 +297,6 @@ require('net').connect(-1); // throws RangeError, port should be > 0 && < 65536 Node.js will generate and throw RangeError instances *immediately* -- they are a form of argument validation. -### Class: TypeError - -A subclass of Error that indicates that a provided argument is not an allowable -type. For example, passing a function to a parameter which expects a string would -be considered a TypeError. - -```javascript -require('url').parse(function() { }); // throws TypeError, since it expected a string -``` - -Node.js will generate and throw TypeError instances *immediately* -- they are a form -of argument validation. - ### Class: ReferenceError A subclass of Error that indicates that an attempt is being made to access a variable @@ -238,6 +342,19 @@ try { SyntaxErrors are unrecoverable from the context that created them – they may only be caught by other contexts. +### Class: TypeError + +A subclass of Error that indicates that a provided argument is not an allowable +type. For example, passing a function to a parameter which expects a string would +be considered a TypeError. + +```javascript +require('url').parse(function() { }); // throws TypeError, since it expected a string +``` + +Node.js will generate and throw TypeError instances *immediately* -- they are a form +of argument validation. + ### Exceptions vs. Errors @@ -262,46 +379,49 @@ subclasses, but instead an error instance with added members. ### Class: System Error -#### error.syscall - -A string representing the [syscall](http://man7.org/linux/man-pages/man2/syscall.2.html) that failed. - -#### error.errno #### error.code +#### error.errno A string representing the error code, which is always `E` followed by capital letters, and may be referenced in `man 2 intro`. +#### error.syscall + +A string representing the [syscall](http://man7.org/linux/man-pages/man2/syscall.2.html) that failed. + ### Common System Errors This list is **not exhaustive**, but enumerates many of the common system errors when writing a Node.js program. An exhaustive list may be found [here](http://man7.org/linux/man-pages/man3/errno.3.html). -#### EPERM: Operation not permitted +#### EACCES: Permission denied -An attempt was made to perform an operation that requires appropriate -privileges. +An attempt was made to access a file in a way forbidden by its file access +permissions. -#### ENOENT: No such file or directory +#### EADDRINUSE: Address already in use -Commonly raised by [fs](fs.html) operations; a component of the specified pathname -does not exist -- no entity (file or directory) could be found by the given path. +An attempt to bind a server ([net](net.html), [http](http.html), or [https](https.html)) to a local +address failed due to another server on the local system already occupying +that address. -#### EACCES: Permission denied +#### ECONNREFUSED: Connection refused -An attempt was made to access a file in a way forbidden by its file access -permissions. +No connection could be made because the target machine actively refused +it. This usually results from trying to connect to a service that is inactive +on the foreign host. + +#### ECONNRESET: Connection reset by peer + +A connection was forcibly closed by a peer. This normally results +from a loss of the connection on the remote socket due to a timeout +or reboot. Commonly encountered via the [http](http.html) and [net](net.html) modules. #### EEXIST: File exists An existing file was the target of an operation that required that the target not exist. -#### ENOTDIR: Not a directory - -A component of the given pathname existed, but was not a directory as expected. -Commonly raised by [fs.readdir](fs.html#fs_fs_readdir_path_callback). - #### EISDIR: Is a directory An operation expected a file, but the given pathname was a directory. @@ -317,154 +437,34 @@ on systems (in particular, OS X) where there is a low file descriptor limit for processes. To remedy a low limit, run `ulimit -n 2048` in the same shell that will run the Node.js process. -#### EPIPE: Broken pipe +#### ENOENT: No such file or directory -A write on a pipe, socket, or FIFO for which there is no process to read the -data. Commonly encountered at the [net](net.html) and [http](http.html) layers, indicative that -the remote side of the stream being written to has been closed. +Commonly raised by [fs](fs.html) operations; a component of the specified pathname +does not exist -- no entity (file or directory) could be found by the given path. -#### EADDRINUSE: Address already in use +#### ENOTDIR: Not a directory -An attempt to bind a server ([net](net.html), [http](http.html), or [https](https.html)) to a local -address failed due to another server on the local system already occupying -that address. +A component of the given pathname existed, but was not a directory as expected. +Commonly raised by [fs.readdir](fs.html#fs_fs_readdir_path_callback). -#### ECONNRESET: Connection reset by peer +#### ENOTEMPTY: Directory not empty -A connection was forcibly closed by a peer. This normally results -from a loss of the connection on the remote socket due to a timeout -or reboot. Commonly encountered via the [http](http.html) and [net](net.html) modules. +A directory with entries was the target of an operation that requires +an empty directory -- usually [fs.unlink](fs.html#fs_fs_unlink_path_callback). -#### ECONNREFUSED: Connection refused +#### EPERM: Operation not permitted -No connection could be made because the target machine actively refused -it. This usually results from trying to connect to a service that is inactive -on the foreign host. +An attempt was made to perform an operation that requires appropriate +privileges. -#### ENOTEMPTY: Directory not empty +#### EPIPE: Broken pipe -A directory with entries was the target of an operation that requires -an empty directory -- usually [fs.unlink](fs.html#fs_fs_unlink_path_callback). +A write on a pipe, socket, or FIFO for which there is no process to read the +data. Commonly encountered at the [net](net.html) and [http](http.html) layers, indicative that +the remote side of the stream being written to has been closed. #### ETIMEDOUT: Operation timed out A connect or send request failed because the connected party did not properly respond after a period of time. Usually encountered by [http](http.html) or [net](net.html) -- often a sign that a connected socket was not `.end()`'d appropriately. - -## Error Propagation and Interception - - - -All Node.js APIs will treat invalid arguments as exceptional -- that is, if passed -invalid arguments, they will *immediately* generate and throw the error as an -exception, even if they are an otherwise asynchronous API. - -Synchronous APIs (like -[fs.readFileSync](fs.html#fs_fs_readfilesync_filename_options)) will throw the -error. The act of *throwing* a value (in this case, the error) turns the value -into an **exception**. Exceptions may be caught using the `try { } catch(err) -{ }` construct. - -Asynchronous APIs have **two** mechanisms for error propagation; one mechanism -for APIs that represent a single operation, and one for APIs that represent -multiple operations over time. - -### Node style callbacks - - - -Single operation APIs take "node style callbacks" -- a -function provided to the API as an argument. The node style callback takes -at least **one** argument -- `error` -- that will either be `null` (if no error -was encountered) or an `Error` instance. For instance: - -```javascript -var fs = require('fs'); - -fs.readFile('/some/file/that/does-not-exist', function nodeStyleCallback(err, data) { - console.log(err) // Error: ENOENT - console.log(data) // undefined / null -}); - -fs.readFile('/some/file/that/does-exist', function(err, data) { - console.log(err) // null - console.log(data) // -}) -``` - -Note that `try { } catch(err) { }` **cannot** intercept errors generated by -asynchronous APIs. A common mistake for beginners is to try to use `throw` -inside their node style callback: - -```javascript -// THIS WILL NOT WORK: -var fs = require('fs'); - -try { - fs.readFile('/some/file/that/does-not-exist', function(err, data) { - // mistaken assumption: throwing here... - if (err) { - throw err; - } - }); -} catch(err) { - // ... will be caught here -- this is incorrect! - console.log(err); // Error: ENOENT -} -``` - -This will not work! By the time the node style callback has been called, the -surrounding code (including the `try { } catch(err) { }` will have already -exited. Throwing an error inside a node style callback **will crash the process** in most cases. -If [domains](domain.html) are enabled, they may intercept the thrown error; similarly, if a -handler has been added to `process.on('uncaughtException')`, it will intercept -the error. - -### Error events - - - -The other mechanism for providing errors is the "error" event. This is -typically used by [stream-based](stream.html) and [event emitter-based](events.html#events_class_events_eventemitter) APIs, which -themselves represent a series of asynchronous operations over time (versus a -single operation that may pass or fail). If no "error" event handler is -attached to the source of the error, the error will be thrown. At this point, -it will crash the process as an unhandled exception unless [domains](domain.html) are -employed appropriately or [process.on('uncaughtException')](process.html#process_event_uncaughtexception) has a handler. - -```javascript -var net = require('net'); - -var connection = net.connect('localhost'); - -// adding an "error" event handler to a stream: -connection.on('error', function(err) { - // if the connection is reset by the server, or if it can't - // connect at all, or on any sort of error encountered by - // the connection, the error will be sent here. - console.error(err); -}); - -connection.pipe(process.stdout); -``` - -The "throw when no error handlers are attached behavior" is not limited to APIs -provided by Node.js -- even user created event emitters and streams will throw -errors when no error handlers are attached. An example: - -```javascript -var EventEmitter = require('events'); - -var ee = new EventEmitter(); - -setImmediate(function() { - // this will crash the process because no "error" event - // handler has been added. - ee.emit('error', new Error('This will crash')); -}); -``` - -As with node style callbacks, errors generated this way *cannot* be intercepted -by `try { } catch(err) { }` -- they happen *after* the calling code has already -exited.