Skip to main content

@arcscord/better-error

A lightweight extension of the native Error class that adds structured debug context. When something goes wrong deep in a call stack, it is often useful to attach extra information — the file that was being processed, the value that caused the issue, the step that failed — without having to encode everything into the error message string.

BaseError accepts a debugs object alongside the message, keeping diagnostic data structured and inspectable rather than buried in a formatted string. It also supports error chaining via originalError, auto-generated UUIDs for error tracking, and formatted stack traces. It is used throughout the arcscord ecosystem as the base class for all framework errors.

Install

pnpm add @arcscord/better-error

Basic usage

import { BaseError } from "@arcscord/better-error";

const err = new BaseError({
message: "Failed to load config",
debugs: {
path: "/etc/bot/config.json",
reason: "file not found",
},
});

console.error(err.message); // "Failed to load config"
console.error(err.getDebugsObject()); // { path: "...", reason: "...", stack1: "...", ... }

Constructor options

new BaseError(options: string | ErrorOptions)

Accepts either a plain string (used as the message) or an options object:

OptionTypeDefaultDescription
messagestringThe error message.
namestring"baseError"The error name, shown in stack traces.
originalErrorBaseError | ErrorThe underlying error that caused this one.
debugsRecord<string, unknown>Arbitrary key/value pairs attached to the error.
autoGenerateIdbooleanfalseAutomatically generate a UUID v4 ID.
customIdstringManually set an ID instead of auto-generating.

Error chaining

Pass the original error as originalError to preserve the cause chain. Its debugs and stack are included in getDebugsObject() by default.

try {
JSON.parse(rawInput);
} catch (cause) {
throw new BaseError({
message: "Invalid bot configuration",
originalError: cause instanceof Error ? cause : new Error(String(cause)),
debugs: { rawInput },
});
}

Error IDs

IDs are useful for correlating a user-facing error message with a log entry.

// Auto-generate a UUID
const err = new BaseError({ message: "Oops", autoGenerateId: true });
console.log(err.id); // "f47ac10b-58cc-..."

// Or assign one manually
const err2 = new BaseError({ message: "Oops", customId: "ERR_001" });

// Or generate after construction
const err3 = new BaseError("Oops").generateId();

Getting debug information

getDebugsObject(options?)

Returns all debug data as an object. Includes the error ID, custom debugs, stack trace, and original error debugs by default.

err.getDebugsObject();
// {
// errorId: "...",
// path: "/etc/bot/config.json",
// reason: "file not found",
// stack1: "Error: Failed to load config",
// stack2: " at ...",
// ...
// }
OptionTypeDefaultDescription
idbooleantrueInclude the error ID.
originalErrorDebugsboolean | GetDebugOptionstrueInclude original error's debugs.
stackbooleantrueInclude the stack trace.
stackFormat"default" | "split""split""split" gives one key per line (stack1, stack2, …). "default" gives a single stack string.
originalErrorStackbooleantrueInclude the original error's stack.

getDebugString(options?)

Same as getDebugsObject() but all values are stringified — useful for structured logging systems that expect Record<string, string>.

fullMessage()

Returns "{name}: {message}".

err.fullMessage(); // "baseError: Failed to load config"

Utility: stringifyUnknown

Converts any value to a string. Used internally by getDebugString().

import { stringifyUnknown } from "@arcscord/better-error";

stringifyUnknown(null); // "null"
stringifyUnknown("hello"); // '"hello"'
stringifyUnknown({ a: 1 }); // '{"a":1}'
stringifyUnknown(undefined); // "undefined"