Error Types
envpkt uses discriminated union types for errors. Each error has a _tag field for pattern matching.
ConfigError
Section titled “ConfigError”Errors from loading and parsing envpkt.toml.
type ConfigError = | { readonly _tag: "FileNotFound"; readonly path: string } | { readonly _tag: "ParseError"; readonly message: string } | { readonly _tag: "ValidationError"; readonly errors: List<string> } | { readonly _tag: "ReadError"; readonly message: string }| Tag | When |
| ----------------- | ---------------------------------------------- |
| FileNotFound | The specified config file does not exist |
| ParseError | TOML syntax error |
| ValidationError | Schema validation failed (with list of errors) |
| ReadError | File system read error |
CatalogError
Section titled “CatalogError”Errors from catalog resolution.
type CatalogError = | { readonly _tag: "CatalogNotFound"; readonly path: string } | { readonly _tag: "CatalogLoadError"; readonly message: string } | { readonly _tag: "SecretNotInCatalog"; readonly key: string; readonly catalogPath: string } | { readonly _tag: "MissingSecretsList"; readonly message: string }| Tag | When |
| -------------------- | --------------------------------------------- |
| CatalogNotFound | The catalog file path does not exist |
| CatalogLoadError | Catalog file failed to load or parse |
| SecretNotInCatalog | Agent references a key not defined in catalog |
| MissingSecretsList | Agent uses catalog but has no secrets array |
FnoxError
Section titled “FnoxError”Errors from fnox integration.
type FnoxError = | { readonly _tag: "FnoxNotFound"; readonly message: string } | { readonly _tag: "FnoxCliError"; readonly message: string } | { readonly _tag: "FnoxParseError"; readonly message: string }| Tag | When |
| ---------------- | ------------------------------- |
| FnoxNotFound | fnox CLI or config not found |
| FnoxCliError | fnox command execution failed |
| FnoxParseError | fnox output could not be parsed |
IdentityError
Section titled “IdentityError”Errors from agent identity operations.
type IdentityError = | { readonly _tag: "IdentityNotFound"; readonly path: string } | { readonly _tag: "IdentityUnreadable"; readonly path: string; readonly message: string } | (IdentityFileError & { readonly source: string })
type IdentityFileError = | { readonly _tag: "NoIdentityKey" } | { readonly _tag: "PassphraseProtectedIdentity" } | { readonly _tag: "UnsupportedIdentity"; readonly kind: "plugin" | "ssh" | "unknown"; readonly line: number }source is the key file’s path, or ENVPKT_AGE_KEY for the inline key. None of these errors
carries key material; describeIdentityError(err) turns any of them into a message.
| Tag | When |
| ----------------------------- | ------------------------------------------------------------------------ |
| IdentityNotFound | Key file not found at the given path |
| IdentityUnreadable | Key file exists but can’t be read (permissions, a directory, I/O error) |
| NoIdentityKey | The key source has no AGE-SECRET-KEY-… line |
| PassphraseProtectedIdentity | The key file is passphrase-protected; unwrap it once with age -d |
| UnsupportedIdentity | A line is an age plugin key, an SSH key, or not a key; line says which |
In boot(), any of these stops boot when sealed values are declared, even under warnOnly.
KeygenError
Section titled “KeygenError”Errors from key generation and config update operations.
type KeygenError = | { readonly _tag: "KeygenFailed"; readonly message: string } | { readonly _tag: "KeyExists"; readonly path: string } | { readonly _tag: "WriteError"; readonly message: string } | { readonly _tag: "ConfigUpdateError"; readonly message: string }| Tag | When |
| ------------------- | ------------------------------------------------------- |
| KeygenFailed | Key generation failed |
| KeyExists | Identity file already exists (no overwrite; pass -o) |
| WriteError | Failed to write identity file or create directory |
| ConfigUpdateError | Failed to read/write envpkt.toml for recipient update |
AliasError
Section titled “AliasError”Errors from validating from_key alias references in envpkt.toml. Raised at
config load time before any secret resolution begins.
type AliasError = | { readonly _tag: "AliasInvalidSyntax" readonly key: string readonly kind: "secret" | "env" readonly value: string } | { readonly _tag: "AliasTargetMissing"; readonly key: string; readonly target: string } | { readonly _tag: "AliasSelfReference"; readonly key: string } | { readonly _tag: "AliasChained"; readonly key: string; readonly target: string } | { readonly _tag: "AliasCrossType" readonly key: string readonly kind: "secret" | "env" readonly targetKind: "secret" | "env" } | { readonly _tag: "AliasValueConflict" readonly key: string readonly kind: "secret" | "env" readonly field: string }| Tag | When |
| -------------------- | ----------------------------------------------------------------------------------- |
| AliasInvalidSyntax | from_key is not formatted as "secret.<KEY>" or "env.<KEY>" |
| AliasTargetMissing | from_key references a target that doesn’t exist in the resolved config |
| AliasSelfReference | An entry’s from_key points at itself |
| AliasChained | The target is itself an alias (only single-hop aliasing is supported) |
| AliasCrossType | A secret entry aliases an env entry or vice versa (same-type aliasing only) |
| AliasValueConflict | The entry declares both from_key and a value field (encrypted_value or value) |
McpHeadersError
Section titled “McpHeadersError”Returned by buildMcpHeaders and printed by envpkt headers. McpConfigError is the subset that validateMcpHeaders returns.
type McpConfigError = | { readonly _tag: "McpHeaderInvalid"; readonly key: string; readonly server: string; readonly header: string } | { readonly _tag: "McpSchemeInvalid"; readonly key: string; readonly server: string; readonly scheme: string } | { readonly _tag: "McpHeaderDuplicate" readonly server: string readonly header: string readonly keys: ReadonlyArray<string> }
type McpHeadersError = | McpConfigError | { readonly _tag: "McpServerUnknown"; readonly server: string } | { readonly _tag: "McpValueUnresolved"; readonly server: string; readonly keys: ReadonlyArray<string> } | { readonly _tag: "McpValueInvalid"; readonly server: string; readonly keys: ReadonlyArray<string> }| Tag | When |
| -------------------- | ----------------------------------------------------------------------------- |
| McpHeaderInvalid | A header is not a valid HTTP header name (empty, spaces, : and so on) |
| McpSchemeInvalid | A non-empty scheme is not a single HTTP token (e.g. "Bearer token") |
| McpHeaderDuplicate | Two bindings claim the same (server, header) pair (header case-insensitive) |
| McpServerUnknown | No secret’s mcp list names the requested server |
| McpValueUnresolved | A bound secret has no value, or an empty one, after resolution |
| McpValueInvalid | A bound value contains a line break or NUL, so it can’t be sent as a header |
BootError
Section titled “BootError”Union of all error types that can occur during boot:
type BootError = | ConfigError | FnoxError | CatalogError | AliasError | { readonly _tag: "AuditFailed"; readonly audit: AuditResult; readonly message: string } | { readonly _tag: "SealKeyUnavailable" readonly sealedKeys: ReadonlyArray<string> readonly searched: ReadonlyArray<string> readonly configuredKeyFile?: string } | IdentityErrorThe AuditFailed variant includes the full AuditResult for inspection. SealKeyUnavailable
means sealed values are declared but no age key was found anywhere; searched lists each place
envpkt looked, in order. Boot refuses rather than inject empty values, even under warnOnly.
Pattern Matching
Section titled “Pattern Matching”Use _tag for exhaustive pattern matching:
import type { ConfigError } from "envpkt"
function handleError(err: ConfigError): string { switch (err._tag) { case "FileNotFound": return `Config not found: ${err.path}` case "ParseError": return `TOML syntax error: ${err.message}` case "ValidationError": return `Validation failed: ${err.errors.toArray().join(", ")}` case "ReadError": return `Read error: ${err.message}` }}Or use functype’s Either.fold:
loadConfig("envpkt.toml").fold( (err) => console.error(`[${err._tag}]`, err), (config) => console.log("Loaded:", config),)