ErrLookup › Background articles › The base Error class: deliberate library guards and refused operations
The base Error class: deliberate library guards and refused operations
This family is the generic Error that a library throws on purpose, from its own code, when a caller violates a precondition it is not willing to paper over. A developer meets it not because of a type slip or a runtime engine fault, but because the library has decided that a configuration value, a payload shape, an environment, or a security posture is wrong enough that guessing would be worse than stopping. Across 54 repositories these throws share one shape — a synchronous, hand-worded message at a trust boundary — while differing widely in what triggered them.
Distilled from 3,783 documented records across 54 repositories.
Background
The throw lives in the library layer, almost always at a trust boundary: a constructor (multer's FileAppender, chalk's Chalk), a setter (chalk.level, got's https setter), the entry of a public method (moment.duration().as, knex's transaction wrapper), or a build/worker task (moment's grunt transpile, prettier's playground worker, vue's release script). It is the library's own assertion, not the engine's. Where a TypeError signals a wrong type and a RangeError signals a numeric boundary, these base Errors signal a wrong value of the right type, or a state the library considers unreachable from its public surface. The message is the contract: it names the offending value, the set of accepted alternatives, or the remediation step the author wants the caller to take.
The reason the family exists is fail-fast. Several records state the alternative explicitly — knex refuses to emit a malformed UPDATE with no SET clause rather than run it; got refuses a cross-origin hop that could leak credentials; lodash refuses to guess whether a function is native under core-js; openclaw refuses to downgrade TLS to system trust silently. In each case the library declines to produce silently-wrong, undefined, or insecure behavior, and throws instead. The throw is the safer failure. Some guards are framed as programmer errors that abort immediately (multer's unknown strategy), others as operational refusals that include the configured context in the message (openclaw's missing certificate file, vscode's missing API key).
From the caller's side most of these surface as a synchronous throw at the call site that can be caught and read. A meaningful subset is not reachable through the documented public API at all: multer's strategy error only fires if an underscore-prefixed internal is called without its second argument; knex's `defaults('foo')` only fires if a custom ColumnCompiler subclass calls it for an unregistered label; dotnet's `Expected ... to be a function` only fires if the wasm import object was mutated externally. These are guards against subclassing, monkey-patching, and fork drift as much as against user error. A few guards are dev-only and elided in production builds — vue's `Invalid async component load result` runs only in __DEV__, so a production bundle silently renders nothing where a dev build would have thrown. Build-time and worker variants (moment transpile, prettier plugin load) surface in task runners or browser consoles rather than application code.
How the family varies across libraries tracks what each library is protecting. Some validate configuration shape against a fixed option set (chalk's level 0-3, got's recognized https keys, gstack's CSS-property regex). Some refuse on a security or integrity condition (knex's unsafe transaction, got's same-origin rule, lodash's core-js native detection, openclaw's mTLS half-pair and retired DeepInfra endpoint). Some guard the environment or platform (esbuild's cross-platform binary, ws's browser stub). Some validate a payload or response shape (knex's empty update, vue's non-component async resolution, openclaw's non-object CDP /json/version, firecrawl's wrapped DB insert). The records also disagree on a deliberate point: some echo the offending value in the message (multer's trailing space implies the strategy stringified to empty; knex echoes table and column keys), while others withhold it as potentially sensitive (openclaw omits the configured TLS path, esbuild omits credential-bearing URLs). That choice is library-specific, not a rule of the family.
Common causes
- Invalid configuration value. The most common trigger: a value that is the right type but outside the accepted set. Chalk rejects a level that is not a safe integer in 0-3; got rejects an unrecognized https key (a typo'd `rejectUnauthroized`, or `ca` instead of `certificateAuthority`); moment rejects a duration unit that normalizes to something durations don't support, including calendar-only units like 'date'. The library knows the valid set and refuses everything else.
- Missing required configuration or credentials. A required pairing or credential is absent. vscode's xtab endpoint throws when no API key resolves from any source; openclaw throws when a configured TLS certificate or key file is missing, empty, or unreadable, and again when only one half of an mTLS cert/key pair is configured. The guard fails closed rather than sending an unauthenticated or half-formed request.
- Misuse of internal or private APIs. Several guards are unreachable from the public surface and only fire through subclassing, monkey-patching, or direct construction of internals. multer's 'Unknown file strategy' fires only if _makeMiddleware is called without its strategy argument; knex's 'no default for identifier' fires only if a custom ColumnCompiler asks for an unregistered label; dotnet's 'Expected ... to be a function' fires only if the wasm import object was mutated. The throw tells you the internal contract was broken.
- Security-sensitive refusal. The library declines an operation it considers insecure rather than silently downgrade. got refuses a URL whose resolved origin differs from prefixUrl when allowAbsoluteUrls is false; knex refuses to begin a transaction on a strict SQLite client without an explicit enforceForeignCheck; lodash throws rather than guess nativeness under core-js. In each case the guard protects a trust boundary and the fix is to correct the condition, not to disable the guard.
- Environment or platform mismatch. The runtime does not match what the package was built for. esbuild throws when node_modules contains a platform binary for a different OS/arch (built on macOS and copied into a Linux image, or mixed under Rosetta 2); ws throws synchronously on import in a browser bundle because it depends on Node core modules. Both fail at module load rather than break later.
- Empty or wrong-shaped payload or response. The data handed to or received from a layer is not the shape the layer will act on. knex's update compiler throws when every value in the payload is undefined after filtering; vue's async loader throws when the resolved value is a non-null primitive instead of a component; openclaw throws when a CDP /json/version endpoint returns non-object JSON; firecrawl wraps and re-throws DB insert failures other than unique-constraint violations.
- Build, tooling, or worker pipeline breakage. A subset fires outside application code, in build tasks and web workers. moment's transpile task throws when requested locales need a parent that was not bundled; prettier's playground worker throws when a language plugin dynamic import rejects; vue's release script throws when the target version fails semver.valid. These surface in task runners or browser consoles and reflect a broken pipeline rather than a broken request.
What usually fixes it
- Validate external input before it reaches the library. Parse and range-check values sourced from env vars or CLI strings (chalk's level), spell-check option names against the documented set (got's https keys), and confirm a unit string is a real duration unit before calling moment.duration().as. The libraries guard late; guarding early gives a clearer, earlier failure.
- Use the documented public API and treat underscore-prefixed or internal methods as private. The multer strategy and knex defaults guards exist precisely because internals assume invariants the public methods guarantee. If you must subclass or monkey-patch, preserve the internal contract (forward every argument, register every label on _defaultMap) and add a smoke test in CI.
- Understand the threat model before loosening a security guard. For got's same-origin rule, knex's unsafe transaction, and lodash's core-js native detection, the correct fix is to correct the configuration or redesign the call (use a separate instance, pass the explicit option, switch to a capability check) rather than to suppress the throw. openclaw's TLS and mTLS errors are fixed by providing complete, readable material or by unsetting the env vars entirely.
- Keep build and runtime environments consistent. Do not copy node_modules or wasm artifacts across OS/arch boundaries; run installs inside the target image and declare supported architectures in your package manager config. For dev-only guards that production builds elide (vue's async-component check), exercise the path in dev or CI so a bad resolution fails before ship.
- Treat no-op and degenerate cases as legitimate application states and short-circuit before the call. For knex's empty update, check that the payload has at least one defined value and skip the query when nothing changed; for vue's async loader, map named exports explicitly and provide an errorComponent. The library refuses to emit a malformed query or render a blank, so the caller should not hand it one.
- Read the embedded context before changing anything. Most messages carry the offending value, the valid set, or a remediation pointer (esbuild names the platform mismatch and suggests esbuild-wasm; openclaw points to 'openclaw doctor --fix'; knex echoes the table and original column keys). Several records note the configured value is deliberately omitted as sensitive, so the absence of a path or URL in the message is intentional, not a bug.
Go deeper
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Documented occurrences
- Unknown file strategy: (expressjs/multer)
- You probably specified locales requiring parent locale, but didn't specify parent (moment/moment)
- Invalid CSS property name: ${property}. Only letters and hyphens allowed. (garrytan/gstack)
- Configured OpenTelemetry ${params.label} file is missing, empty, or unreadable; refusing insecure export (openclaw/openclaw)
- Refusing to create an unsafe transaction: client.strictForeignKeyPragma is true, but check.enforceForeignCheck is unspecified (knex/knex)
- Unknown unit ${units} (moment/moment)
- Configured OpenTelemetry mTLS requires both a client certificate and private key; refusing insecure export (openclaw/openclaw)
- telegram runtime unavailable (runtime keys: ${runtimeKeys.join(",")}; channel keys: ${channelKeys.join(",")}) (openclaw/openclaw)
- Discord guild admin actions require a trusted Discord sender identity. (openclaw/openclaw)
- Invalid async component load result: ${comp} (vuejs/vue)
- Missing API key for custom URL (${this.urlOrRequestMetadata}). Provide the API key using vscode setting `github.copilot.chat.advanced.inlineEdits.xtabProvider.apiKey` or, if in simulations using `--nes-api-key` or `--config-file` (microsoft/vscode)
- DeepInfra video generation requires an OpenAI-compatible endpoint, but models.providers.deepinfra.baseUrl targets the retired native /v1/inference surface. Run "openclaw doctor --fix" (api.deepinfra.com migrates automatically; custom hosts must set baseUrl to an OpenAI-compatible videos endpoint). (openclaw/openclaw)
- There is no default for the specified identifier ${label} (knex/knex)
- ws does not work in the browser. Browser clients must use the native WebSocket object (websockets/ws)
- Failed to insert monitor email recipient: ${error instanceof Error ? error.message : JSON.stringify(error)} (firecrawl/firecrawl)
- You installed esbuild for another platform than the one you're currently using. This won't work because esbuild is written with native code and needs to install a platform-specific binary executable. ${suggestions} Another alternative is to use the "esbuild-wasm" package instead, which works the same way on all platforms. But it comes with a heavy performance cost and can sometimes be 10x slower than the "esbuild" package, so you may also not want to do that. (evanw/esbuild)
- invalid target version: ${targetVersion} (vuejs/vue)
- The `url` option must stay on the same origin as `prefixUrl` when `allowAbsoluteUrls` is false (sindresorhus/got)
- CDP /json/version returned non-object JSON (openclaw/openclaw)
- Load plugin '${plugin.file}' failed. (prettier/prettier)
…and 3,763 more across the corpus — use search.
Honest provenance: generated on 2026-08-12 from AI-assisted analysis of the linked records. See how records are made.