mirror of https://github.com/nodejs/node.git
doc: add error documentation
PR-URL: https://github.com/iojs/io.js/pull/789 Reviewed-by: Rod Vagg <rod@vagg.org> Reviewed-By: Trevor Norris <trev.norris@gmail.com> Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com>
This commit is contained in:
parent
d832be4aa3
commit
7e2235aebb
|
@ -12,6 +12,7 @@
|
|||
* [Debugger](debugger.html)
|
||||
* [DNS](dns.html)
|
||||
* [Domain](domain.html)
|
||||
* [Errors](errors.html)
|
||||
* [Events](events.html)
|
||||
* [File System](fs.html)
|
||||
* [Globals](globals.html)
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
@include dgram
|
||||
@include dns
|
||||
@include domain
|
||||
@include errors
|
||||
@include events
|
||||
@include fs
|
||||
@include globals
|
||||
|
|
|
@ -0,0 +1,470 @@
|
|||
# Errors
|
||||
|
||||
<!--type=misc-->
|
||||
|
||||
Errors generated by io.js fall into two categories: JavaScript errors and system
|
||||
errors. All errors inherit from or are instances of JavaScript's [Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)
|
||||
class and are guaranteed to provide *at least* the attributes available on that
|
||||
class.
|
||||
|
||||
When an operation is not permitted due to language-syntax or
|
||||
language-runtime-level reasons, a **JavaScript error** is generated and thrown
|
||||
as an **exception**. If an operation is not allowed due to system-level
|
||||
restrictions, a **system error** is generated. Client code is then given the
|
||||
opportunity to **intercept** this error based on how the API **propagates** it.
|
||||
|
||||
The style of API called determines how generated errors are handed back, or
|
||||
**propagated**, to client code, which in turn informs how the client may **intercept**
|
||||
the error. Exceptions can be intercepted using the `try / catch` construct;
|
||||
other propagation strategies are covered [below](#errors_error_propagation_and_interception).
|
||||
|
||||
## JavaScript Errors
|
||||
|
||||
<!--type=misc-->
|
||||
|
||||
JavaScript errors typically denote that an API is being used incorrectly, or that
|
||||
there is a problem with the program as written.
|
||||
|
||||
### Class: Error
|
||||
|
||||
<!--type=class-->
|
||||
|
||||
A general error object. Unlike other error objects, `Error` instances do not
|
||||
denote any specific circumstance of why the error occurred. Errors capture a
|
||||
"stack trace" detailing the point in the program at which they were
|
||||
instantiated, and may provide a description of the error.
|
||||
|
||||
**Note**: io.js will generate this class of error to encapsulate system
|
||||
errors as well as plain JavaScript errors.
|
||||
|
||||
#### new Error(message)
|
||||
|
||||
Instantiates a new Error object and sets its `.message` property to the provided
|
||||
message. Its `.stack` will represent the point in the program at which `new Error`
|
||||
was called. Stack traces are subject to [V8's stack trace API](https://code.google.com/p/v8-wiki/wiki/JavaScriptStackTraceApi).
|
||||
Stack traces only extend to the beginning of synchronous code execution, *or* a number of frames given by
|
||||
`Error.stackTraceLimit`, whichever is smaller.
|
||||
|
||||
#### error.message
|
||||
|
||||
A string of the value passed to `Error()` upon instantiation. The message will
|
||||
also appear in the first line of the stack trace of the error. Changing this
|
||||
property *may not* change the first line of the stack trace.
|
||||
|
||||
#### error.stack
|
||||
|
||||
A property that, when **accessed**, returns a string representing the point in the program
|
||||
at which this error was instantiated. An example stacktrace follows:
|
||||
|
||||
Error: Things keep happening!
|
||||
at /home/gbusey/file.js:525:2
|
||||
at Frobnicator.refrobulate (/home/gbusey/business-logic.js:424:21)
|
||||
at Actor.<anonymous> (/home/gbusey/actors.js:400:8)
|
||||
at increaseSynergy (/home/gbusey/actors.js:701:6)
|
||||
|
||||
The first line is formatted as `<error class name>: <error message>`, and it is followed
|
||||
by a series of stack frames (each line beginning with "at "). Each frame describes
|
||||
a call site in the program that lead to the error being generated. V8 attempts to
|
||||
display a name for each function (by variable name, function name, or object
|
||||
method name), but occasionally it will not be able to find a suitable name. If
|
||||
V8 cannot determine a name for the function, only location information will be
|
||||
displayed for that frame. Otherwise, the determined function name will be displayed
|
||||
with location information appended in parentheses.
|
||||
|
||||
Frames are **only** generated for JavaScript functions. If, for example, execution
|
||||
synchronously passes through a C++ addon function called `cheetahify`, which itself
|
||||
calls a JavaScript function, the frame representing the `cheetahify` call will **not**
|
||||
be present in stacktraces:
|
||||
|
||||
```javascript
|
||||
var cheetahify = require('./native-binding.node');
|
||||
|
||||
function makeFaster() {
|
||||
// cheetahify *synchronously* calls speedy.
|
||||
cheetahify(function speedy() {
|
||||
throw new Error('oh no!');
|
||||
});
|
||||
}
|
||||
|
||||
makeFaster(); // will throw:
|
||||
// /home/gbusey/file.js:6
|
||||
// throw new Error('oh no!');
|
||||
// ^
|
||||
// Error: oh no!
|
||||
// at speedy (/home/gbusey/file.js:6:11)
|
||||
// at makeFaster (/home/gbusey/file.js:5:3)
|
||||
// at Object.<anonymous> (/home/gbusey/file.js:10:1)
|
||||
// at Module._compile (module.js:456:26)
|
||||
// at Object.Module._extensions..js (module.js:474:10)
|
||||
// at Module.load (module.js:356:32)
|
||||
// at Function.Module._load (module.js:312:12)
|
||||
// at Function.Module.runMain (module.js:497:10)
|
||||
// at startup (node.js:119:16)
|
||||
// at node.js:906:3
|
||||
```
|
||||
|
||||
The location information will be one of:
|
||||
|
||||
* `native`, if the frame represents a call internal to V8 (as in `[].forEach`).
|
||||
* `plain-filename.js:line:column`, if the frame represents a call internal to io.js.
|
||||
* `/absolute/path/to/file.js:line:column`, if the frame represents a call in a user program, or its dependencies.
|
||||
|
||||
It is important to note that the string representing the stacktrace is only
|
||||
generated on **access**: it is lazily generated.
|
||||
|
||||
The number of frames captured by the stack trace is bounded by the smaller of
|
||||
`Error.stackTraceLimit` or the number of available frames on the current event
|
||||
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 effect 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
|
||||
set or range of acceptable values for a function; whether that be a numeric
|
||||
range, or outside the set of options for a given function parameter. An example:
|
||||
|
||||
```javascript
|
||||
require('net').connect(-1); // throws RangeError, port should be > 0 && < 65536
|
||||
```
|
||||
|
||||
io.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
|
||||
```
|
||||
|
||||
io.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
|
||||
that is not defined. Most commonly it indicates a typo, or an otherwise broken program.
|
||||
While client code may generate and propagate these errors, in practice only V8 will do
|
||||
so.
|
||||
|
||||
```javascript
|
||||
doesNotExist; // throws ReferenceError, doesNotExist is not a variable in this program.
|
||||
```
|
||||
|
||||
ReferenceError instances will have an `.arguments` member that is an array containing
|
||||
one element -- a string representing the variable that was not defined.
|
||||
|
||||
```javascript
|
||||
try {
|
||||
doesNotExist;
|
||||
} catch(err) {
|
||||
err.arguments[0] === 'doesNotExist';
|
||||
}
|
||||
```
|
||||
|
||||
Unless the userland program is dynamically generating and running code,
|
||||
ReferenceErrors should always be considered a bug in the program, or its
|
||||
dependencies.
|
||||
|
||||
### Class: SyntaxError
|
||||
|
||||
A subclass of Error that indicates that a program is not valid JavaScript.
|
||||
These errors may only be generated and propagated as a result of code
|
||||
evaluation. Code evaluation may happen as a result of `eval`, `Function`,
|
||||
`require`, or [vm](vm.html). These errors are almost always indicative of a broken
|
||||
program.
|
||||
|
||||
```javascript
|
||||
try {
|
||||
require("vm").runInThisContext("binary ! isNotOk");
|
||||
} catch(err) {
|
||||
// err will be a SyntaxError
|
||||
}
|
||||
```
|
||||
|
||||
SyntaxErrors are unrecoverable from the context that created them – they may only be caught
|
||||
by other contexts.
|
||||
|
||||
### Exceptions vs. Errors
|
||||
|
||||
<!--type=misc-->
|
||||
|
||||
A JavaScript "exception" is a value that is thrown as a result of an invalid operation or
|
||||
as the target of a `throw` statement. While it is not required that these values inherit from
|
||||
`Error`, all exceptions thrown by io.js or the JavaScript runtime *will* be instances of Error.
|
||||
|
||||
Some exceptions are *unrecoverable* at the JavaScript layer. These exceptions will always bring
|
||||
down the process. These are usually failed `assert()` checks or `abort()` calls in the C++ layer.
|
||||
|
||||
## System Errors
|
||||
|
||||
System errors are generated in response to a program's runtime environment.
|
||||
Ideally, they represent operational errors that the program needs to be able to
|
||||
react to. They are generated at the syscall level: an exhaustive list of error
|
||||
codes and their meanings is available by running `man 2 intro` on most Unices;
|
||||
or [online](http://man7.org/linux/man-pages/man2/intro.2.html).
|
||||
|
||||
In io.js, system errors are represented as augmented Error objects -- not full
|
||||
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
|
||||
|
||||
A string representing the error code, which is always `E` followed by capital
|
||||
letters, and may be referenced in `man 2 intro`.
|
||||
|
||||
### Common System Errors
|
||||
|
||||
This list is **not exhaustive**, but enumerates many of the common system errors when
|
||||
writing a io.js program. An exhaustive list may be found [here](http://man7.org/linux/man-pages/man2/intro.2.html).
|
||||
|
||||
#### EPERM: Operation not permitted
|
||||
|
||||
An attempt was made to perform an operation that requires appropriate
|
||||
privileges.
|
||||
|
||||
#### ENOENT: No such file or directory
|
||||
|
||||
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.
|
||||
|
||||
#### EACCES: Permission denied
|
||||
|
||||
An attempt was made to access a file in a way forbidden by its file access
|
||||
permissions.
|
||||
|
||||
#### 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.
|
||||
|
||||
#### EMFILE: Too many open files in system
|
||||
|
||||
Maxiumum number of [file descriptors](http://en.wikipedia.org/wiki/File_descriptor) allowable on the system has
|
||||
been reached, and requests for another descriptor cannot be fulfilled until
|
||||
at least one has been closed.
|
||||
|
||||
Commonly encountered when opening many files at once in parallel, especially
|
||||
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 io.js process.
|
||||
|
||||
#### EPIPE: Broken pipe
|
||||
|
||||
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.
|
||||
|
||||
#### EADDRINUSE: Address already in use
|
||||
|
||||
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.
|
||||
|
||||
#### 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.
|
||||
|
||||
#### ECONNREFUSED: Connection refused
|
||||
|
||||
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.
|
||||
|
||||
#### ENOTEMPTY: Directory not empty
|
||||
|
||||
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).
|
||||
|
||||
#### 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
|
||||
|
||||
<!--type=misc-->
|
||||
|
||||
All io.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
|
||||
|
||||
<!--type=misc-->
|
||||
|
||||
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) // <Buffer: ba dd ca fe>
|
||||
})
|
||||
```
|
||||
|
||||
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
|
||||
|
||||
<!--type=misc-->
|
||||
|
||||
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 io.js -- even user created event emitters and streams will throw
|
||||
errors when no error handlers are attached. An example:
|
||||
|
||||
```javascript
|
||||
var events = require('events');
|
||||
|
||||
var ee = new events.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.
|
Loading…
Reference in New Issue