Blog

Lightweight Express Error Middleware and a TypeScript CLI Probe

A typed Express middleware for 5xx responses, plus a CLI probe, without a second logging vendor. Both come from @aethellayer/sdk.

2026-10-23 · 3 min read · AethelLayer

What you see

Express already has an error handler, and it logs a line. The CLI next to it logs a different line. Neither asks what the developer was doing, and neither leaves a draft. Adding a heavy agent for both paths is more code than the bug.

Root cause

5xx responses often pass through next(err) or simply finish the response with a status. A logging middleware that only wraps next(err) misses a handler that sent 500 and returned. A CLI probe that only wraps Node exceptions misses exit 137. You want one client with two hooks, both typed.

The middleware

Aethel.express() returns an Express-compatible middleware: (req, res, next). On finish, status codes of 500 and above are captured as HTTP_<status>. A throw before next is captured as UNCAUGHT_MIDDLEWARE and re-passed to next(err).

Aethel.next() registers uncaughtException and unhandledRejection for the Next.js Node instrumentation hook. nextMiddleware() is the request helper when you already have a middleware chain that returns a response status.

Wire it

bashnpx --yes @aethellayer/sdk init

Express:

tsimport express from "express";import { Aethel } from "@aethellayer/sdk"; const app = express();const aethel = new Aethel({ apiKey: process.env.AETHEL_API_KEY! });app.use(aethel.express());

Next.js instrumentation:

tsexport async function register() {  if (process.env.NEXT_RUNTIME === "nodejs") {    const { Aethel } = await import("@aethellayer/sdk");    new Aethel({ apiKey: process.env.AETHEL_API_KEY! }).next();  }}

The CLI uses the same package. The constructor sends one start signal when the key is set. That signal does not open an inbox thread. Captured 5xx responses do.

Capture the failure before they leave

Install the probe. It drafts the GitHub issue. You still send it.

npx --yes @aethellayer/sdk init