Skip to content

[Feature]: Error handling system #36

Description

@nehu3n

Summary

Add a type-safe error handling system using a builder pattern for defining custom errors, with support for error handlers at multiple specificity levels.

Motivation

Currently Kito doesn't have a structured way to handle errors. Developers need a clean, type-safe approach to:

  • Define custom errors with specific status codes and context data
  • Handle errors at different levels (specific error, by code, catch-all)
  • Get full TypeScript inference when throwing and handling errors
  • Access error context in handlers

This is essential for building production apps where proper error handling and logging are critical.

Proposed Solution

Defining errors

Use a builder pattern to create type-safe error definitions:

import { error } from "kitojs";

const UserNotFound = error("USER_NOT_FOUND")
  .status(404)
  .message("User not found")
  .data<{ userId: string }>()
  .build();

const ValidationError = error("VALIDATION_ERROR")
  .status(400)
  .message((data: { fields: string[] }) => `Validation failed: ${data.fields.join(", ")}`)
  .data()
  .build();

Throwing errors

app.get("/users/:id", ({ req, res }) => {
  const user = db.find(req.params.id);
  
  if (!user) {
    throw UserNotFound({ userId: req.params.id });
  }
  
  res.json(user);
});

Handling errors

Support multiple handler levels:

// Specific error handler
app.onError(UserNotFound, async ({ error, res }) => {
  await logger.warn(`User ${error.data.userId} not found`);
  res.status(error.status).json({ error: error.code });
});

// By error code
app.onError("VALIDATION_ERROR", ({ error, res }) => {
  res.status(400).json({ fields: error.data.fields });
});

// Multiple specific errors
app.onError([UserNotFound, OtherError], ({ error, res }) => {});

Observing errors

For logging, metrics, or other side-effects that should always run regardless of handling:

app.observeError(({ error, ctx }) => {});
Fallback for unhandled errors

Executes only if no other handler consumed the error:

app.onUnhandledError(({ error, res }) => {
  res.status(500).json({ error: "internal_error" });
});

Built-in errors

Export common framework errors:

import { KitoErrors } from "kitojs";

throw KitoErrors.RouteNotFound();
throw KitoErrors.MethodNotAllowed({ allowed: ["GET", "POST"] });
throw KitoErrors.PayloadTooLarge({ limit: "10mb" });

Future considerations

  • Error recovery/retry logic
  • Error transformation chains
  • Error context propagation

Checklist

  • I've searched for related issues
  • I've read the documentation

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions