Error reporting

Fail fast on invalid env with clear console output and structured issues.

Edit on GitHub

ArkEnv throws at the call site when a required variable is missing or a value fails the schema. Bad config stays out of running processes, builds, and plugin runs.

What you see in the console

Invalid input raises ArkEnvError. The message lists every failing path:

Errors found while validating environment variables
  PORT must be an integer between 0 and 65535 (was "abc")
  DATABASE_URL is required

Paths are highlighted; the header is red when ANSI color is available.

Most apps let that throw stop the process. You do not need a try/catch around every arkenv() call. Catch only when you want to inspect ArkEnvError yourself (custom boot UI, tests, or a wrapper):

./boot.ts
import arkenv, { ArkEnvError } from "@arkenv/core";

try {
  arkenv(
    {
      PORT: "number.port",
      DATABASE_URL: "string",
    },
    { env: { PORT: "abc" } },
  );
} catch (error) {
  if (error instanceof ArkEnvError) {
    console.error(error.message);
    console.error(error.issues);
  }
  throw error;
}

Issue codes

Each entry in error.issues includes a machine-readable code:

CodeTypical cause
MISSING_VARIABLERequired key absent
INVALID_TYPEValue could not match the declared type
VALUE_TOO_SMALL / VALUE_TOO_LARGENumeric or length bounds
PATTERN_MISMATCHString failed a pattern
INVALID_FORMATFormat keyword failed (for example host/port)
UNDECLARED_KEYExtra key with onUndeclaredKey: "reject"
INVALID_SCHEMASchema itself is invalid
CUSTOMValidator-specific failure

Use these codes in CI scripts and health checks instead of scraping message text.

Secret redaction

Values for sensitive keys are redacted in error output by default. Leave that alone in CI and production.

debugSecrets: true (or ARKENV_DEBUG_SECRETS=1) prints the raw value. Treat it as a local escape hatch only.

Do not enable secret debugging in shared logs. Redaction exists so a failed boot does not print credentials.

Safe mode

Fail-fast arkenv() from @arkenv/core (and @arkenv/standard) always throws. Import arkenv from the /safe subpath when you want a result object instead of a throw (tests, custom boot UI):

./env.ts
import  from "@arkenv/core/safe";

const  = (
  { : "number.port" },
  { : { : "nope" } },
);

if (!.) {
  .(.);
}

@arkenv/standard mirrors the same shape via @arkenv/standard/safe. Framework integrations (Next.js, Nuxt, Vite, Bun) do not expose a non-throwing path — invalid env still fails the build or server start there on purpose.

Framework boundary errors

Reading a server-only key from client code is a misuse, not a schema failure. The throw is a native Error (so Vite/Bun client modules never import ArkEnvError). name stays "Error". The message is an instruction, same shape as Next.js taint copy, with ArkEnv at the end so agents can attribute it:

Error: Do not access server-only key 'DATABASE_URL' on the client since it will leak sensitive data (prevented by ArkEnv)

Do not catch this. Fix the access. instanceof ArkEnvError is for schema failures only — it is false here because there are no issues.

Next.js, Nuxt, Vite, and Bun each enforce the boundary (runtime proxy and/or build transforms). See client vs. server.

Next steps