errorcore
Capturing Errors

Request Context

Request context answers the basic operational questions around a failure: which route broke, which method hit it, and whether a request identifier can tie the incident back to server logs or traces.

If you use one of the built-in middleware integrations, request context is attached automatically. The middleware reads the method, URL, and filtered headers from the incoming request and creates an async context that follows the request through its lifecycle.

automatic context via middleware
import express from "express";
import errorcore, { expressMiddleware } from "errorcore";

errorcore.init({
  service: "checkout-api",
  transport: { type: "file", path: "./errors.ndjson" },
  allowUnencrypted: true,
});

const app = express();
app.use(expressMiddleware());

// any error thrown inside a route handler now includes
// the request method, URL, and filtered headers
app.get("/orders/:id", async (req, res) => {
  const order = await db.orders.findById(req.params.id);
  if (!order) throw new Error("order not found");
  res.json(order);
});

Manual context

For code paths outside a framework (background jobs, queue consumers, scheduled tasks), use withContext to create a scope manually:

manual context scope
import errorcore from "errorcore";

errorcore.withContext(() => {
  // errors thrown here are captured with a context scope,
  // so IO and state reads are grouped into the same incident
  processQueueMessage(message);
});

What gets captured

Each request context records:

  • request method and URL
  • request ID (from x-request-id or x-correlation-id headers, if present)
  • filtered headers (sensitive headers are excluded by default)
  • request body, if captureRequestBodies is enabled

Header filtering

The header filter is controlled by headerAllowlist and headerBlocklist in the SDK config. The defaults keep safe operational headers and drop anything matching sensitive patterns:

default behavior
// allowed by default
// content-type, content-length, accept, user-agent,
// x-request-id, x-correlation-id, host

// blocked by default (regex match)
// authorization, cookie, set-cookie, x-api-key,
// x-auth-token, and anything containing auth, token,
// key, secret, password, or credential

You can override these lists if your service needs different filtering:

custom header filtering
errorcore.init({
  service: "internal-api",
  transport: { type: "file", path: "./errors.ndjson" },
  headerAllowlist: ["content-type", "x-request-id", "x-tenant-id"],
  headerBlocklist: [/authorization|cookie|secret/i],
  allowUnencrypted: true,
});

Keep the captured shape narrow. Context should identify the request, not mirror the full payload.

On this page