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.
Errors
Union type representing all possible CLI error conditions.
Signature
type CliError = UnrecognizedOption | DuplicateOption | MissingOption | MissingArgument | UnexpectedArgument | InvalidValue | UnknownSubcommand | ShowHelp | UserErrorExample 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"DuplicateOption
unstableError 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"InvalidValue
unstableError 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 argumentsconst invalidArgError = new CliError.InvalidValue({ option: "count", value: "abc", expected: "integer", kind: "argument"})
const details = [invalidArgError.kind, invalidArgError.option, invalidArgError.value] // => ["argument", "count", "abc"]MissingArgument
unstableError 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 parsingconst 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"MissingOption
unstableError 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 contextconst 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"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.TypeError 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;}UnexpectedArgument
unstableError 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"]]UnknownSubcommand
unstableError 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 parsingconst 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"UnrecognizedOption
unstableError 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 errorconst 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 contextconst parseCommand = Effect.gen(function*() { // If parsing encounters unknown flag return yield* unrecognizedError})
const parseError = await Effect.runPromise(Effect.flip(parseCommand))parseError._tag // => "UnrecognizedOption"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 errorsconst userError = new CliError.UserError({ cause: new Error("Database connection failed for postgres://localhost"), userMessage: "Could not connect to the database"})
// In command handlerconst deployCommand = Effect.gen(function*() { const result = yield* Effect.try({ try: () => ({ deployed: true }), catch: (error) => new CliError.UserError({ cause: error }) }) return result})
// In error handlingconst 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)) // => 1Guards
isCliError
unstableType guard to check if a value is a CLI error.
Signature
declare function isCliError(u: unknown): u is CliErrorExample 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
NonShowHelpErrors
unstableSchema 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]>