Human-friendly and powerful HTTP request library for Node.js
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Comprehensive error classes with detailed metadata for different failure scenarios, providing rich context for debugging and error recovery.
The base error class for all Got-related request failures.
/**
* Base error class for request failures
* Contains detailed request/response metadata and timing information
*/
class RequestError<T = unknown> extends Error {
/**
* Error name identifier
*/
readonly name: "RequestError";
/**
* Error code (e.g., ECONNREFUSED, ETIMEDOUT)
*/
readonly code: string;
/**
* Request options that were used
*/
readonly options: Options;
/**
* Response object if available
*/
readonly response?: Response<T>;
/**
* Request object
*/
readonly request?: Request;
/**
* Request timing information
*/
readonly timings?: Timings;
/**
* Original input that caused the error
*/
input?: string;
/**
* Create a new RequestError
* @param message - Error message
* @param error - Original error object
* @param self - Request or Options object
*/
constructor(message: string, error: Partial<Error & {code?: string}>, self: Request | Options);
}Usage Examples:
import got, { RequestError } from "got";
try {
const response = await got("https://nonexistent.example.com");
} catch (error) {
if (error instanceof RequestError) {
console.log("Error code:", error.code); // e.g., "ENOTFOUND"
console.log("Request URL:", error.options.url);
console.log("Request method:", error.options.method);
if (error.timings) {
console.log("Request duration:", error.timings.phases?.total);
}
}
}Error thrown for HTTP responses with non-2xx status codes (when throwHttpErrors is true).
/**
* Error for HTTP responses with error status codes
* Always includes response object with status code and body
*/
class HTTPError<T = any> extends RequestError<T> {
/**
* Error name identifier
*/
readonly name: "HTTPError";
/**
* Error code
*/
readonly code: "ERR_NON_2XX_3XX_RESPONSE";
/**
* HTTP response object (always present)
*/
readonly response: Response<T>;
/**
* Request object (always present)
*/
readonly request: Request;
/**
* Request timings (always present)
*/
readonly timings: Timings;
/**
* Create a new HTTPError
* @param response - HTTP response object
*/
constructor(response: PlainResponse);
}Usage Examples:
import got, { HTTPError } from "got";
try {
const response = await got("https://api.example.com/users/999");
} catch (error) {
if (error instanceof HTTPError) {
console.log("HTTP Status:", error.response.statusCode); // 404
console.log("Status Message:", error.response.statusMessage); // "Not Found"
console.log("Response Body:", error.response.body);
console.log("Request URL:", error.response.requestUrl);
// Handle specific status codes
switch (error.response.statusCode) {
case 404:
console.log("Resource not found");
break;
case 401:
console.log("Authentication required");
break;
case 429:
console.log("Rate limited");
break;
default:
console.log("HTTP error:", error.response.statusCode);
}
}
}Error thrown when the request exceeds the maximum number of allowed redirects.
/**
* Error for excessive redirects
* Thrown when request exceeds maxRedirects limit
*/
class MaxRedirectsError extends RequestError {
/**
* Error name identifier
*/
readonly name: "MaxRedirectsError";
/**
* Error code
*/
readonly code: "ERR_TOO_MANY_REDIRECTS";
/**
* Final response object (always present)
*/
readonly response: Response;
/**
* Request object (always present)
*/
readonly request: Request;
/**
* Request timings (always present)
*/
readonly timings: Timings;
/**
* Create a new MaxRedirectsError
* @param request - Request object
*/
constructor(request: Request);
}Usage Examples:
import got, { MaxRedirectsError } from "got";
try {
const response = await got("https://example.com/infinite-redirect", {
maxRedirects: 5
});
} catch (error) {
if (error instanceof MaxRedirectsError) {
console.log("Too many redirects");
console.log("Final URL:", error.response.url);
console.log("Redirect chain:", error.response.redirectUrls);
console.log("Max redirects allowed:", error.request.options.maxRedirects);
}
}Error thrown when various timeout limits are exceeded during the request.
/**
* Error for request timeouts
* Thrown when any timeout limit is exceeded
*/
class TimeoutError extends RequestError {
/**
* Error name identifier
*/
readonly name: "TimeoutError";
/**
* Error code indicating timeout type
*/
readonly code: string; // "ETIMEDOUT", "ESOCKETTIMEDOUT", etc.
/**
* Which timeout was exceeded
*/
readonly timings: Timings;
/**
* Timeout event that triggered the error
*/
readonly event: string;
/**
* Create a new TimeoutError
* @param error - Timeout error details
* @param timings - Request timing information
* @param request - Request object
*/
constructor(error: TimeoutErrorOptions, timings: Timings, request: Request);
}
interface TimeoutErrorOptions {
event: string;
threshold: number;
}Usage Examples:
import got, { TimeoutError } from "got";
try {
const response = await got("https://slow-api.example.com", {
timeout: {
request: 5000, // 5 second overall limit
response: 3000 // 3 second response limit
}
});
} catch (error) {
if (error instanceof TimeoutError) {
console.log("Timeout event:", error.event); // "request", "response", etc.
console.log("Timeout code:", error.code);
if (error.timings) {
console.log("Time elapsed:", error.timings.phases?.total);
}
}
}Other specific error types for various failure scenarios.
/**
* Error for cache-related failures
*/
class CacheError extends RequestError {
readonly name: "CacheError";
readonly code: "ERR_CACHE_ACCESS";
}
/**
* Error for request body upload failures
*/
class UploadError extends RequestError {
readonly name: "UploadError";
readonly code: "ERR_UPLOAD";
}
/**
* Error for response body reading failures
*/
class ReadError extends RequestError {
readonly name: "ReadError";
readonly code: "ERR_READING_RESPONSE_STREAM";
}
/**
* Error to force request retries
*/
class RetryError extends RequestError {
readonly name: "RetryError";
readonly code: "ERR_RETRYING";
}
/**
* Error for aborted requests (via AbortController)
*/
class AbortError extends RequestError {
readonly name: "AbortError";
readonly code: "ERR_ABORTED";
}
/**
* Error for response body parsing failures
*/
class ParseError extends RequestError {
readonly name: "ParseError";
readonly code: "ERR_BODY_PARSE_FAILURE";
}
/**
* Error for canceled promises
*/
class CancelError extends RequestError {
readonly name: "CancelError";
readonly code: "ERR_CANCELED";
/**
* Whether the promise is canceled
*/
get isCanceled(): boolean;
}Common patterns for handling different types of errors.
Basic Error Handling:
import got, { RequestError, HTTPError, TimeoutError } from "got";
async function fetchData(url: string) {
try {
const response = await got(url).json();
return response;
} catch (error) {
if (error instanceof HTTPError) {
// Handle HTTP errors (4xx, 5xx status codes)
switch (error.response.statusCode) {
case 404:
throw new Error("Resource not found");
case 429:
throw new Error("Rate limited - try again later");
case 500:
throw new Error("Server error - try again later");
default:
throw new Error(`HTTP error: ${error.response.statusCode}`);
}
} else if (error instanceof TimeoutError) {
// Handle timeout errors
throw new Error("Request timed out - server is slow");
} else if (error instanceof RequestError) {
// Handle other request errors (network, DNS, etc.)
switch (error.code) {
case "ENOTFOUND":
throw new Error("DNS lookup failed - check URL");
case "ECONNREFUSED":
throw new Error("Connection refused - server may be down");
case "ECONNRESET":
throw new Error("Connection reset - network issue");
default:
throw new Error(`Network error: ${error.code}`);
}
} else {
// Handle unexpected errors
throw error;
}
}
}Retry with Error Handling:
import got, { HTTPError, RequestError } from "got";
async function fetchWithRetry(url: string, maxRetries: number = 3) {
let lastError: Error;
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const response = await got(url, {
timeout: { request: 10000 },
retry: { limit: 0 } // Handle retries manually
});
return response;
} catch (error) {
lastError = error;
if (error instanceof HTTPError) {
// Don't retry client errors (4xx)
if (error.response.statusCode >= 400 && error.response.statusCode < 500) {
throw error;
}
} else if (error instanceof RequestError) {
// Don't retry permanent failures
if (["ENOTFOUND", "EINVAL"].includes(error.code)) {
throw error;
}
}
// Wait before retry (exponential backoff)
if (attempt < maxRetries) {
const delay = Math.min(1000 * Math.pow(2, attempt - 1), 10000);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}
throw lastError!;
}Graceful Error Handling:
import got, { RequestError } from "got";
async function safeRequest(url: string) {
try {
const response = await got(url, {
throwHttpErrors: false, // Don't throw on HTTP errors
timeout: { request: 5000 },
retry: { limit: 2 }
});
return {
success: response.statusCode >= 200 && response.statusCode < 300,
status: response.statusCode,
body: response.body,
error: null
};
} catch (error) {
return {
success: false,
status: 0,
body: null,
error: error instanceof RequestError ? {
code: error.code,
message: error.message,
type: error.constructor.name
} : {
code: "UNKNOWN",
message: error.message,
type: "Unknown"
}
};
}
}All Got errors include rich metadata for debugging and error recovery:
| Property | Description | Availability |
|---|---|---|
code | Error code (ENOTFOUND, ETIMEDOUT, etc.) | All errors |
options | Request options used | All errors |
request | Request object | Most errors |
response | Response object | HTTP errors |
timings | Request timing data | Most errors |
retryCount | Number of retries attempted | After retries |
redirectUrls | Redirect chain | After redirects |