Cognition: Error Capture

How Cognition catches errors automatically and manually, builds breadcrumb trails, parses V8 stack frames, and enriches events with user context and severity levels.

Cognition catches errors two ways: automatically, through global process handlers installed at startup, and manually, through captureError() and captureMessage(). Either way, every event arrives at Skytells with the full stack trace, a breadcrumb history, user context, tags, and runtime metadata already attached.


Automatic Error Capture

When captureErrors: true (the default), the SDK installs two global process handlers at init() time:

HandlerSeverityWhat it catches
uncaughtExceptionfatalSynchronous errors that propagate to the top of the call stack without being caught
unhandledRejectionerrorPromise rejections not handled with .catch()
// Automatically captured as fatal
setTimeout(() => {
  throw new Error('Unexpected failure');
}, 1000);

// Automatically captured as error
async function fetchData() {
  const res = await fetch('https://api.example.com/data');
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
}
fetchData(); // No .catch() — Cognition captures this

These handlers are cleanly removed during cognition.close() and never interfere with your own handlers.


Manual Error Capture

captureError()

Capture a caught error explicitly with optional context:

try {
  await riskyOperation();
} catch (err) {
  cognition.captureError(err as Error, {
    level: 'error',              // Override the default severity
    context: {
      userId: 'u-123',
      action: 'checkout',
      cartTotal: 99.99,
    },
  });
}

The context object is merged into the event's extra field alongside any global extra data set via setExtra().

captureMessage()

Capture a plain message string without an Error object:

cognition.captureMessage('User signed up', 'info');
cognition.captureMessage('Payment failed after 3 retries', 'warning');
cognition.captureMessage('Quota limit approaching', 'warning');

captureEvent()

Send a fully constructed event of any type through the transport pipeline:

cognition.captureEvent({
  type: 'business_metric',
  timestamp: Date.now(),
  metric: 'order_total',
  value: 149.99,
  orderId: 'ord-456',
});

Custom events pass through the same beforeSend hook, ring buffer, and batching as all built-in event types.


Severity Levels

LevelMeaningDefault for
fatalUnrecoverable — process should exituncaughtException
errorSignificant error, handled but notableunhandledRejection, manual captureError() default
warningNotable but not an errorManual capture
infoInformationalcaptureMessage() default
debugVerbose diagnostic informationManual capture

Context Enrichment

Every error event is automatically enriched from multiple sources before being buffered:

Per-capture context (captureError options)  ──┐
Global extra (setExtra)   ────────────────────┤──► error.extra
Global tags (setTag)      ────────────────────┤──► error.tags
User (setUser)            ────────────────────┤──► error.user
Breadcrumbs               ────────────────────┤──► error.breadcrumbs
Config (environment, release, serverName)     ┤──► error.environment / release / serverName
Runtime (node version)    ────────────────────┤──► error.runtime
OS (platform, kernel version) ────────────────┘──► error.os

setUser()

Attach user identity to all subsequent events:

cognition.setUser({
  id: 'user-123',
  email: '[email protected]',
  username: 'jane_doe',
});

// Clear user on logout
cognition.setUser(undefined);

setTag()

Tags are indexed and searchable in the Console:

cognition.setTag('service', 'payment-api');
cognition.setTag('region', 'us-east-1');
cognition.setTag('version', '2.1.0');

setExtra()

Attach arbitrary key-value data:

cognition.setExtra('requestId', 'req-abc-123');
cognition.setExtra('retryCount', 3);
cognition.setExtra('featureFlag', 'new-checkout-flow');

Breadcrumbs are a trail of events recorded before an error occurs. When an error is captured, the most recent breadcrumbs are snapshot and attached to the error event.

Automatic Breadcrumbs (Console Patching)

When captureErrors: true, the SDK monkey-patches console methods to silently record breadcrumbs. Original output still happens — Cognition only intercepts, it never suppresses.

Console MethodBreadcrumb Level
console.debugdebug
console.loginfo
console.infoinfo
console.warnwarning
console.errorerror

Original console.* methods are restored during cognition.close().

Manual Breadcrumbs

// Category, message, optional data, optional level
cognition.addBreadcrumb('http', 'GET /api/users → 200', { durationMs: 45 });
cognition.addBreadcrumb('database', 'Fetched user record', { userId: 'u-123' });
cognition.addBreadcrumb('user-action', 'Clicked "Submit Order"');
cognition.addBreadcrumb('navigation', 'Redirected to /checkout', undefined, 'info');

Parameters:

ParameterTypeDescription
categorystringGrouping category: 'http', 'database', 'user-action', etc.
messagestringHuman-readable description
dataRecord<string, unknown>?Arbitrary structured data
levelSeverityLevel?Default: 'info'

The internal BreadcrumbCollector maintains a circular buffer of the most recent 100 breadcrumbs. When an error occurs, all current breadcrumbs are snapshot and attached to the event — the buffer is not cleared.

interface Breadcrumb {
  timestamp: number;            // Unix ms
  category: string;             // e.g. 'console', 'http', 'database'
  message: string;              // Human-readable description
  level: SeverityLevel;         // 'fatal' | 'error' | 'warning' | 'info' | 'debug'
  data?: Record<string, unknown>;
}

Stack Frame Parsing

The SDK parses V8 stack traces into structured StackFrame objects. Given:

Error: Connection refused
    at DatabaseClient.connect (src/db/client.ts:45:12)
    at async handleRequest (src/routes/users.ts:23:5)
    at Layer.handle (node_modules/express/lib/router/layer.js:95:5)
    at node:internal/process/task_queues:95:5

Produces:

[
  { "function": "DatabaseClient.connect", "filename": "src/db/client.ts", "lineno": 45, "colno": 12, "in_app": true },
  { "function": "async handleRequest", "filename": "src/routes/users.ts", "lineno": 23, "colno": 5, "in_app": true },
  { "function": "Layer.handle", "filename": "node_modules/express/lib/router/layer.js", "lineno": 95, "colno": 5, "in_app": false },
  { "filename": "node:internal/process/task_queues", "lineno": 95, "colno": 5, "in_app": false }
]

in_app classification: A frame is in_app: false if its filename contains node_modules or starts with node:. Everything else is in_app: true. This helps the Skytells platform prioritize your application code in analysis.


Error Event Structure

Every captured error produces a fully typed ErrorEvent:

interface ErrorEvent {
  type: 'error';
  timestamp: number;            // Unix ms

  error: {
    name: string;               // e.g. 'TypeError'
    message: string;            // e.g. 'Cannot read properties of undefined'
    stack?: string;             // Raw V8 stack trace
    frames?: StackFrame[];      // Parsed structured frames
  };

  level: SeverityLevel;         // 'fatal' | 'error' | 'warning' | 'info' | 'debug'
  breadcrumbs: Breadcrumb[];    // Recent breadcrumbs
  tags: Record<string, string>; // Global tags
  extra: Record<string, unknown>; // Global extra + per-capture context

  user?: {
    id?: string;
    email?: string;
    username?: string;
  };

  environment: string;          // From config.environment
  release: string;              // From config.release
  serverName: string;           // From config.serverName or os.hostname()

  runtime: {
    name: 'node';
    version: string;            // e.g. '20'
  };

  os: {
    name: string;               // 'darwin', 'linux', 'win32'
    version: string;            // Kernel version
  };

  fingerprint?: string[];
  context?: Record<string, unknown>;
}

Full Example

import { Cognition } from '@skytells/cognition';

const cognition = Cognition.init({
  apiKey: process.env.SKYTELLS_API_KEY!,
  projectId: process.env.SKYTELLS_PROJECT_ID!,
  environment: 'production',
  release: process.env.npm_package_version,
});

// Persistent context — attached to all subsequent events
cognition.setUser({ id: 'u-456', username: 'buyer_jane' });
cognition.setTag('service', 'payments');
cognition.setExtra('region', 'us-east-1');

// Breadcrumbs — recorded as the request flows through your system
cognition.addBreadcrumb('http', 'POST /api/charge → started');
cognition.addBreadcrumb('data', 'Fetched wallet balance', { userId: 'u-456' });

try {
  await chargeCustomer(order);
} catch (err) {
  // Error event will include:
  // - Parsed stack frames with in_app classification
  // - 2 manual breadcrumbs + any console breadcrumbs
  // - User { id: 'u-456', username: 'buyer_jane' }
  // - Tags { service: 'payments' }
  // - Extra { region: 'us-east-1', orderId: order.id }
  // - environment, release, serverName, runtime, os
  cognition.captureError(err as Error, {
    context: { orderId: order.id },
  });
}

  • Quickstart — Initialize the SDK and send your first event
  • ConfigurationcaptureErrors, beforeSend, environment, release options
  • Analytics — View captured errors in the Console and CLI

How is this guide?

On this page