| name | aidd-error-causes |
| description | Use the error-causes library for structured error handling in JavaScript/TypeScript. Use when throwing errors, catching errors, defining error types, or implementing error routing. |
Error Causes Rule
Use the error-causes library for all error handling in JavaScript/TypeScript code to enable structured error handling with named causes.
Why Error Causes?
- Enables structured error handling with named causes instead of relying on
instanceof checks
- Works across memory realms (e.g., iframes) unlike
instanceof
- Provides consistent error metadata (name, code, message, cause)
- Makes error handling explicit and self-documenting
- Allows for automatic error routing based on error names
Import Statement
import { createError } from "error-causes";
Basic Usage
Instead of throwing plain errors:
throw new Error('Config key "API_KEY" is required');
Use createError with structured metadata:
throw createError({
name: 'ConfigurationError',
message: 'Required configuration key "API_KEY" is not defined',
code: 'MISSING_CONFIG_KEY',
requestedKey: 'API_KEY'
});
Error Properties
Always include these properties in createError:
name - Error name for matching (e.g., 'ValidationError', 'AuthenticationError')
message - Human-readable error message
code (optional) - Error code for programmatic handling
- Custom properties (optional) - Any additional context relevant to the error
Wrapping Caught Errors
When catching and re-throwing errors, preserve the original error as cause:
try {
await someOperation();
} catch (originalError) {
throw createError({
name: 'OperationError',
message: 'Failed to perform operation',
code: 'OPERATION_FAILED',
cause: originalError
});
}
Factory Validation Errors
For factory functions that validate parameters at creation time:
const createMiddleware = ({ requiredParam } = {}) => {
if (!requiredParam) {
throw createError({
name: 'ValidationError',
message: 'requiredParam is required',
code: 'MISSING_REQUIRED_PARAM'
});
}
return async ({ request, response }) => {
};
};
Testing Error Causes
In tests, verify the error's cause property:
let error;
try {
functionThatThrows();
} catch (e) {
error = e;
}
assert({
given: 'invalid input',
should: 'throw Error with cause',
actual: error instanceof Error && error.cause !== undefined,
expected: true
});
assert({
given: 'invalid input',
should: 'have correct error name',
actual: error.cause.name,
expected: 'ValidationError'
});
assert({
given: 'invalid input',
should: 'have correct error code',
actual: error.cause.code,
expected: 'MISSING_REQUIRED_PARAM'
});
Error Handler Pattern
For APIs that define multiple error types, use the errorCauses pattern:
import { errorCauses, createError } from "error-causes";
const [apiErrors, handleApiErrors] = errorCauses({
NotFound: {
code: 404,
message: 'Resource not found'
},
ValidationError: {
code: 400,
message: 'Invalid input'
},
Unauthorized: {
code: 401,
message: 'Authentication required'
}
});
const { NotFound, ValidationError, Unauthorized } = apiErrors;
if (!resource) throw createError(NotFound);
someAsyncCall()
.catch(handleApiErrors({
NotFound: ({ message }) => console.log(message),
ValidationError: ({ message }) => console.log(message),
Unauthorized: ({ message }) => redirect('/login')
}));
Rules
- Always use
createError instead of new Error() for thrown errors
- Always include
name and message in error metadata
- Include
code when the error needs programmatic handling
- Preserve original errors using the
cause property when re-throwing
- Add context with custom properties relevant to the error
- Test the
cause property in error tests, not just the error message
- Define error types using
errorCauses() for APIs with multiple error types