Skip to content
Effect 4.0 is here. One ecosystem. Zero dependencies.

CliError unstable

Defines structured errors for the unstable CLI parser and runner.

CLI errors describe problems such as unknown or duplicate flags, missing flags or arguments, unexpected positional arguments, invalid values, unknown subcommands, user handler failures, and requests to show command help. This module includes the CliError union, the isCliError guard, schema-backed error classes with display messages, and the NonShowHelpErrors union used when parse or validation errors should be shown with help output.

13 exports Since v4.0.0 Source

Errors

CliError

type unstable
Since v4.0.0

Union type representing all possible CLI error conditions.

Signature

type CliError = UnrecognizedOption | DuplicateOption | MissingOption | MissingArgument | UnexpectedArgument | InvalidValue | UnknownSubcommand | ShowHelp | UserError

Example Handling CLI errors

import { CliError } from "effect/cli"
const describe = (error: CliError.CliError): string => {
switch (error._tag) {
case "UnrecognizedOption":
return `Unknown flag: ${error.option}`
case "MissingOption":
return `Required flag missing: ${error.option}`
case "InvalidValue":
return `Invalid value: ${error.value} for ${error.option}`
case "ShowHelp":
return `Help requested for: ${error.commandPath.join(" ")}`
default:
return error.message
}
}
describe(new CliError.MissingOption({ option: "token" })) // => "Required flag missing: token"
Since v4.0.0

Error thrown when duplicate option names are detected between parent and child commands.

Signature

declare class DuplicateOption extends {
readonly _tag: "DuplicateOption";
readonly childCommand: string;
readonly option: string;
readonly parentCommand: string;
} & YieldableError<this> {
constructor(...args: [props: {
readonly _tag?: "DuplicateOption";
readonly childCommand: string;
readonly option: string;
readonly parentCommand: string;
}, options?: MakeOptions]);
readonly "~effect/cli/CliError": "~effect/cli/CliError";
message: string;
}

Example Creating duplicate option errors

import { CliError } from "effect/cli"
const duplicateError = new CliError.DuplicateOption({
option: "--verbose",
parentCommand: "myapp",
childCommand: "deploy"
})
duplicateError._tag // => "DuplicateOption"
duplicateError.option // => "--verbose"
duplicateError.parentCommand // => "myapp"
duplicateError.childCommand // => "deploy"
Since v4.0.0

Error thrown when an option or argument value is invalid.

Signature

declare class InvalidValue extends {
readonly _tag: "InvalidValue";
readonly expected: string;
readonly kind: "flag" | "argument";
readonly option: string;
readonly value: string;
} & YieldableError<this> {
constructor(...args: [props: {
readonly _tag?: "InvalidValue";
readonly expected: string;
readonly kind: "flag" | "argument";
readonly option: string;
readonly value: string;
}, options?: MakeOptions]);
readonly "~effect/cli/CliError": "~effect/cli/CliError";
message: string;
}

Example Creating invalid value errors

import { CliError } from "effect/cli"
const invalidValueError = new CliError.InvalidValue({
option: "port",
value: "abc123",
expected: "integer between 1 and 65535",
kind: "flag"
})
invalidValueError._tag // => "InvalidValue"
invalidValueError.kind // => "flag"
invalidValueError.option // => "port"
invalidValueError.value // => "abc123"
// For positional arguments
const invalidArgError = new CliError.InvalidValue({
option: "count",
value: "abc",
expected: "integer",
kind: "argument"
})
const details = [invalidArgError.kind, invalidArgError.option, invalidArgError.value] // => ["argument", "count", "abc"]
Since v4.0.0

Error thrown when a required positional argument is missing.

Signature

declare class MissingArgument extends {
readonly _tag: "MissingArgument";
readonly argument: string;
} & YieldableError<this> {
constructor(...args: [props: {
readonly _tag?: "MissingArgument";
readonly argument: string;
}, options?: MakeOptions]);
readonly "~effect/cli/CliError": "~effect/cli/CliError";
message: string;
}

Example Creating missing argument errors

import { Effect } from "effect"
import { CliError } from "effect/cli"
const missingArgError = new CliError.MissingArgument({
argument: "target"
})
const details = [missingArgError._tag, missingArgError.argument] // => ["MissingArgument", "target"]
// In argument parsing
const parseArguments = (args: Array<string>) =>
Effect.gen(function*() {
if (args.length === 0) {
return yield* missingArgError
}
return args[0]
})
const parseError = await Effect.runPromise(Effect.flip(parseArguments([])))
parseError._tag // => "MissingArgument"
Since v4.0.0

Error thrown when a required option is missing.

Signature

declare class MissingOption extends {
readonly _tag: "MissingOption";
readonly option: string;
} & YieldableError<this> {
constructor(...args: [props: {
readonly _tag?: "MissingOption";
readonly option: string;
}, options?: MakeOptions]);
readonly "~effect/cli/CliError": "~effect/cli/CliError";
message: string;
}

Example Creating missing option errors

import { Effect } from "effect"
import { CliError } from "effect/cli"
const missingOptionError = new CliError.MissingOption({
option: "api-key"
})
const details = [missingOptionError._tag, missingOptionError.option] // => ["MissingOption", "api-key"]
// In validation context
const validateRequiredOptions = (options: Record<string, string | undefined>) =>
Effect.gen(function*() {
const apiKey = options["api-key"]
if (!apiKey) {
return yield* missingOptionError
}
return apiKey
})
const validationError = await Effect.runPromise(Effect.flip(validateRequiredOptions({})))
validationError._tag // => "MissingOption"

NonShowHelpErrors

type unstable
Since v4.0.0

Type of CLI errors that are not ShowHelp.

Details

These errors can be accumulated and attached to ShowHelp.errors when the runner should display help along with the underlying parse or validation failures.

Signature

type NonShowHelpErrors = typeof NonShowHelpErrors.Type

ShowHelp

unstable
Since v4.0.0

Error data requesting CLI help rendering for a command path.

Details

It is used for explicit help requests and for parse or validation failures that should be shown with help text. When errors is non-empty, the runtime exit code is 1; otherwise it is 0.

Signature

declare class ShowHelp extends {
readonly _tag: "ShowHelp";
readonly commandPath: readonly Array<string>;
readonly errors: readonly Array<UnrecognizedOption | DuplicateOption | MissingOption | MissingArgument | UnexpectedArgument | InvalidValue | UnknownSubcommand | UserError>;
} & YieldableError<this> {
constructor(...args: [props: {
readonly _tag?: "ShowHelp";
readonly commandPath: readonly Array<string>;
readonly errors: readonly Array<UnrecognizedOption | DuplicateOption | MissingOption | MissingArgument | UnexpectedArgument | InvalidValue | UnknownSubcommand | UserError>;
}, options?: MakeOptions]);
readonly "~effect/cli/CliError": "~effect/cli/CliError";
readonly "~effect/Runtime/errorExitCode": 0 | 1;
readonly "~effect/Runtime/errorReported": false;
message: string;
}
Since v4.0.0

Error thrown when positional arguments remain after a command has parsed all of its parameters.

Signature

declare class UnexpectedArgument extends {
readonly _tag: "UnexpectedArgument";
readonly arguments: readonly Array<string>;
} & YieldableError<this> {
constructor(...args: [props: {
readonly _tag?: "UnexpectedArgument";
readonly arguments: readonly Array<string>;
}, options?: MakeOptions]);
readonly "~effect/cli/CliError": "~effect/cli/CliError";
message: string;
}

Example Reporting unexpected arguments

import { CliError } from "effect/cli"
const error = new CliError.UnexpectedArgument({
arguments: ["extra.txt"]
})
const details = [error._tag, error.arguments] // => ["UnexpectedArgument", ["extra.txt"]]
Since v4.0.0

Error thrown when an unknown subcommand is encountered.

Signature

declare class UnknownSubcommand extends {
readonly _tag: "UnknownSubcommand";
readonly parent?: readonly Array<string>;
readonly subcommand: string;
readonly suggestions: readonly Array<string>;
} & YieldableError<this> {
constructor(...args: [props: {
readonly _tag?: "UnknownSubcommand";
readonly parent?: readonly Array<string>;
readonly subcommand: string;
readonly suggestions: readonly Array<string>;
}, options?: MakeOptions]);
readonly "~effect/cli/CliError": "~effect/cli/CliError";
message: string;
}

Example Creating unknown subcommand errors

import { Effect } from "effect"
import { CliError } from "effect/cli"
const unknownSubcommandError = new CliError.UnknownSubcommand({
subcommand: "deplyo", // typo
parent: ["myapp"],
suggestions: ["deploy", "destroy"]
})
unknownSubcommandError._tag // => "UnknownSubcommand"
unknownSubcommandError.subcommand // => "deplyo"
unknownSubcommandError.parent // => ["myapp"]
// In subcommand parsing
const parseSubcommand = (subcommand: string) =>
Effect.gen(function*() {
const validCommands = ["deploy", "destroy", "status"]
if (!validCommands.includes(subcommand)) {
return yield* unknownSubcommandError
}
return subcommand
})
const parseError = await Effect.runPromise(Effect.flip(parseSubcommand("deplyo")))
parseError._tag // => "UnknownSubcommand"
Since v4.0.0

Error thrown when an unrecognized option is encountered.

Signature

declare class UnrecognizedOption extends {
readonly _tag: "UnrecognizedOption";
readonly command?: readonly Array<string>;
readonly option: string;
readonly suggestions: readonly Array<string>;
} & YieldableError<this> {
constructor(...args: [props: {
readonly _tag?: "UnrecognizedOption";
readonly command?: readonly Array<string>;
readonly option: string;
readonly suggestions: readonly Array<string>;
}, options?: MakeOptions]);
readonly "~effect/cli/CliError": "~effect/cli/CliError";
message: string;
}

Example Creating unrecognized option errors

import { Effect } from "effect"
import { CliError } from "effect/cli"
// Creating an unrecognized option error
const unrecognizedError = new CliError.UnrecognizedOption({
option: "--unknown-flag",
command: ["deploy", "production"],
suggestions: ["--verbose", "--force"]
})
unrecognizedError._tag // => "UnrecognizedOption"
unrecognizedError.option // => "--unknown-flag"
unrecognizedError.command // => ["deploy", "production"]
// In CLI parsing context
const parseCommand = Effect.gen(function*() {
// If parsing encounters unknown flag
return yield* unrecognizedError
})
const parseError = await Effect.runPromise(Effect.flip(parseCommand))
parseError._tag // => "UnrecognizedOption"

UserError

unstable
Since v4.0.0

Error wrapper for user handler failures in the CLI error channel.

Details

userMessage can provide safe, user-facing text independently of the underlying cause. When omitted or empty, message uses a non-empty string cause or Error.message, then falls back to "An error occurred".

Signature

declare class UserError extends {
readonly _tag: "UserError";
readonly cause: unknown;
readonly userMessage?: string;
} & YieldableError<this> {
constructor(...args: [props: {
readonly _tag?: "UserError";
readonly cause: unknown;
readonly userMessage?: string;
}, options?: MakeOptions]);
readonly "~effect/cli/CliError": "~effect/cli/CliError";
"~effect/Runtime/errorReported": boolean;
message: string;
}

Example Wrapping user errors

import { Effect } from "effect"
import { CliError } from "effect/cli"
// Wrapping user errors
const userError = new CliError.UserError({
cause: new Error("Database connection failed for postgres://localhost"),
userMessage: "Could not connect to the database"
})
// In command handler
const deployCommand = Effect.gen(function*() {
const result = yield* Effect.try({
try: () => ({ deployed: true }),
catch: (error) => new CliError.UserError({ cause: error })
})
return result
})
// In error handling
const handleError = (error: CliError.CliError): Effect.Effect<number> => {
if (error._tag === "UserError") {
return Effect.succeed(1) // Exit code 1
}
return Effect.succeed(0)
}
await Effect.runPromise(deployCommand) // => { deployed: true }
await Effect.runPromise(handleError(userError)) // => 1

Guards

isCliError

unstable
Since v4.0.0

Type guard to check if a value is a CLI error.

Signature

declare function isCliError(u: unknown): u is CliError

Example Checking CLI errors

import { Effect } from "effect"
import { CliError } from "effect/cli"
const error = new CliError.MissingOption({ option: "api-key" })
const program = CliError.isCliError(error)
? Effect.succeed(error.message)
: Effect.fail("Unknown error")
await Effect.runPromise(program) // => "Missing required flag: --api-key"

Schemas

Since v4.0.0

Schema for concrete CLI errors that can be reported together with help output.

Details

This excludes ShowHelp itself, allowing parse and validation errors to be stored in ShowHelp.errors without nesting another help-control value.

Signature

declare const NonShowHelpErrors: Schema.Union<readonly [typeof UnrecognizedOption, typeof DuplicateOption, typeof MissingOption, typeof MissingArgument, typeof UnexpectedArgument, typeof InvalidValue, typeof UnknownSubcommand, typeof UserError]>