/**
* Consistent error formatting and classification for AWS MCP tool errors.
*/
export type ErrorCategory =
| "auth"
| "throttle"
| "validation"
| "not_found"
| "unknown";
export interface ClassifiedError {
category: ErrorCategory;
message: string;
userMessage: string;
}
/**
* Classifies an AWS/Node error and returns a user-friendly message.
* Avoids exposing raw error details to clients.
*/
export function classifyError(error: unknown): ClassifiedError {
const err = error as Error & {
name?: string;
$metadata?: { httpStatusCode?: number };
};
const rawMessage = err?.message ?? String(error);
if (
rawMessage.includes("credentials") ||
rawMessage.includes("Unauthorized") ||
rawMessage.includes("AccessDenied") ||
rawMessage.includes("InvalidClientTokenId") ||
rawMessage.includes("SignatureDoesNotMatch") ||
err?.name === "UnauthorizedException"
) {
return {
category: "auth",
message: rawMessage,
userMessage:
"Authentication or authorization failed. Verify AWS credentials and IAM permissions.",
};
}
if (
rawMessage.includes("Throttling") ||
rawMessage.includes("Rate exceeded") ||
rawMessage.includes("TooManyRequestsException") ||
err?.$metadata?.httpStatusCode === 429
) {
return {
category: "throttle",
message: rawMessage,
userMessage:
"AWS rate limit exceeded. Please retry in a few seconds.",
};
}
if (
rawMessage.includes("validation") ||
rawMessage.includes("ValidationException") ||
rawMessage.includes("InvalidParameter")
) {
return {
category: "validation",
message: rawMessage,
userMessage: `Invalid request: ${rawMessage.slice(0, 200)}`,
};
}
if (
rawMessage.includes("not found") ||
rawMessage.includes("NotFound") ||
rawMessage.includes("does not exist")
) {
return {
category: "not_found",
message: rawMessage,
userMessage: "The requested resource was not found.",
};
}
return {
category: "unknown",
message: rawMessage,
userMessage:
"An error occurred while executing the request. Check your inputs and AWS configuration.",
};
}