Error reporting
Fail fast on invalid env with clear console output and structured issues.
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 requiredPaths 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):
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:
| Code | Typical cause |
|---|---|
MISSING_VARIABLE | Required key absent |
INVALID_TYPE | Value could not match the declared type |
VALUE_TOO_SMALL / VALUE_TOO_LARGE | Numeric or length bounds |
PATTERN_MISMATCH | String failed a pattern |
INVALID_FORMAT | Format keyword failed (for example host/port) |
UNDECLARED_KEY | Extra key with onUndeclaredKey: "reject" |
INVALID_SCHEMA | Schema itself is invalid |
CUSTOM | Validator-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):
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.