Claude-skill-registry add-error-type
Add a new custom error type for domain-specific errors. Use when creating errors for specific business rules or HTTP status codes. Triggers on "add error", "custom error", "error type".
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/add-error-type" ~/.claude/skills/majiayu000-claude-skill-registry-add-error-type && rm -rf "$T"
manifest:
skills/data/add-error-type/SKILL.mdsource content
Add Error Type
Adds a new domain error type that extends
BaseError. All custom errors are defined in src/errors.ts and automatically handled by the global error handler.
Quick Reference
File:
src/errors.ts
Base class: BaseError
Auto HTTP mapping: errorCode number maps to HTTP status
Existing Error Types
| Error Class | HTTP Status | Use Case |
|---|---|---|
| 400 | Invalid input, validation fails |
| 401 | Missing or invalid credentials |
| 403 | Lacks permission for action |
| 404 | Resource doesn't exist |
| 500 | Unexpected server errors |
| 503 | External service down |
Instructions
Step 1: Add Error Class to src/errors.ts
src/errors.tsexport class {ErrorName}Error extends BaseError { constructor( message: string = "Default error message", options?: Omit<BaseErrorOptions, "errorCode">, ) { super(message, { ...options, errorCode: {HTTP_STATUS_CODE} }); } }
Step 2: Use in Services/Controllers
import { {ErrorName}Error } from "@/errors"; // Throw when condition is met if (someCondition) { throw new {ErrorName}Error("Specific error message"); } // With cause for debugging throw new {ErrorName}Error("Error message", { cause: originalError });
Common HTTP Status Codes
| Code | Name | When to Use |
|---|---|---|
| 400 | Bad Request | Malformed request, validation failure |
| 401 | Unauthenticated | No credentials or invalid credentials |
| 403 | Forbidden | Valid credentials but lacks permission |
| 404 | Not Found | Resource doesn't exist |
| 409 | Conflict | Resource state conflict (duplicate, etc) |
| 422 | Unprocessable Entity | Semantic errors in valid syntax |
| 429 | Too Many Requests | Rate limiting |
| 500 | Internal Server Error | Unexpected server-side errors |
| 502 | Bad Gateway | Upstream service returned invalid |
| 503 | Service Unavailable | Server temporarily unavailable |
| 504 | Gateway Timeout | Upstream service timeout |
Examples
Conflict Error (409)
export class ConflictError extends BaseError { constructor( message: string = "Resource conflict", options?: Omit<BaseErrorOptions, "errorCode">, ) { super(message, { ...options, errorCode: 409 }); } } // Usage if (await repository.findByEmail(email)) { throw new ConflictError("User with this email already exists"); }
Rate Limit Error (429)
export class RateLimitError extends BaseError { constructor( message: string = "Too many requests", options?: Omit<BaseErrorOptions, "errorCode">, ) { super(message, { ...options, errorCode: 429 }); } } // Usage if (requestCount > limit) { throw new RateLimitError("Rate limit exceeded. Try again later."); }
Validation Error (422)
export class ValidationError extends BaseError { constructor( message: string = "Validation failed", options?: Omit<BaseErrorOptions, "errorCode">, ) { super(message, { ...options, errorCode: 422 }); } } // Usage with cause containing field errors throw new ValidationError("Invalid input data", { cause: { field: "email", message: "Invalid email format" }, });
Gateway Error (502)
export class BadGatewayError extends BaseError { constructor( message: string = "Bad Gateway", options?: Omit<BaseErrorOptions, "errorCode">, ) { super(message, { ...options, errorCode: 502 }); } } // Usage if (!upstreamResponse.ok) { throw new BadGatewayError("Upstream service returned invalid response"); }
Using HttpError for One-off Status Codes
For status codes that don't need a dedicated class:
import { HttpError } from "@/errors"; // One-off 451 (Unavailable For Legal Reasons) throw new HttpError(451, "Content unavailable in your region"); // One-off 507 (Insufficient Storage) throw new HttpError(507, "Storage quota exceeded");
BaseError Structure
export class BaseError extends Error { public readonly cause?: unknown; public readonly errorCode?: ErrorCode; constructor(message: string, options?: BaseErrorOptions) { super(message); this.name = this.constructor.name; this.cause = options?.cause; this.errorCode = options?.errorCode; Object.setPrototypeOf(this, new.target.prototype); } public toJSON(): { error: string; code?: ErrorCode; cause?: string } { const json: { error: string; code?: ErrorCode; cause?: string } = { error: this.message, }; if (this.errorCode !== undefined) { json.code = this.errorCode; } if (this.cause instanceof Error && this.cause.message) { json.cause = this.cause.message; } return json; } }
Global Error Handler
The
globalErrorHandler in src/errors.ts automatically:
- Logs the error
- Converts
instances to JSON responsesBaseError - Maps
to HTTP statuserrorCode - Wraps unknown errors in
InternalServerError
export const globalErrorHandler = (err: Error, c: Context<AppEnv>) => { console.error(err); if (err instanceof BaseError) { return createErrorResponse(c, err); // Uses errorCode as HTTP status } else if (err instanceof HTTPException) { return c.json({ error: err.message }, err.status); } else { const internalError = new InternalServerError( "An unexpected error occurred", { cause: err }, ); return createErrorResponse(c, internalError); } };
What NOT to Do
- Do NOT catch and re-throw as generic Error (loses type info)
- Do NOT return error responses manually (use error classes)
- Do NOT use non-standard HTTP status codes without good reason
- Do NOT forget to set
(defaults to 500)errorCode - Do NOT put stack traces in error messages (use
for debugging)cause
See Also
- Global error handler setupcreate-middleware
- Error handling in servicescreate-utility-service
- Throwing errors from controllerscreate-controller