SchemaIssue
Describes problems found while decoding, encoding, or checking data with schemas.
An Issue records what failed and, for nested data, where the failure
happened. The Schema system uses these values for missing keys, unexpected
keys, invalid types, invalid values, failed filters, failed transformations,
and alternatives that did not match. This module also formats issues.
Formatting
Callback type used to format Filter issues into strings.
When to use
Use when customizing how makeFormatterStandardSchemaV1 renders filter failures.
Details
- Returns
stringto override the message, orundefinedto fall back to the default formatting.
See
- defaultCheckHook — the built-in implementation
- Filter — the issue type this hook formats
Signature
type CheckHook = (issue: Filter) => string | undefineddefaultCheckHook
Returns the built-in CheckHook used by default formatters.
When to use
Use as the default filter renderer when customizing only the LeafHook.
Details
- Looks for a
messageannotation on the inner issue first, then on the filter itself. - Returns
undefinedwhen no annotation is found, causing the formatter to fall back to"Expected <filter>"or, when the filter reports input,"Expected <filter>, got <input>".
See
Signature
declare const defaultCheckHook: CheckHookdefaultLeafHook
Returns the built-in LeafHook used by default formatters.
When to use
Use as the default leaf renderer when customizing only the CheckHook.
Details
- Checks for a
messageannotation first; returns it if present. - For
InvalidValue, anexpectedannotation uses the standard expected value message and includes reported input when available. - Otherwise generates a default message per
_tag. When the issue reports input, the message includes its formatted value where applicable:InvalidType→"Expected <type>"or"Expected <type>, got <input>"InvalidValue→"Expected a valid value"or"Invalid data <input>"MissingKey→"Missing key"UnexpectedKey→"Expected no excess property"or"Unexpected key with value <input>"Forbidden→"Forbidden operation"OneOf→"Expected exactly one member to match"or"Expected exactly one member to match the input <input>"
See
Signature
declare const defaultLeafHook: LeafHookExample
(Formatting Standard Schema issues with defaultLeafHook)
import { SchemaIssue } from "effect"
const formatter = SchemaIssue.makeFormatterStandardSchemaV1({ leafHook: SchemaIssue.defaultLeafHook})formatter(new SchemaIssue.MissingKey(undefined)) // => { issues: [{ path: [], message: "Missing key" }] }A function type that converts an Issue into a formatted
representation. Specialisation of the generic Formatter from
Formatter.ts with Value fixed to Issue.
See
- makeFormatterDefault — creates a
Formatter<string> - makeFormatterStandardSchemaV1 — creates a
Formatter<StandardSchemaV1.FailureResult>
Signature
interface Formatter<out Format> extends Formatter<Issue, Format> { (value: Issue): Format;}Callback type used to format Leaf issues into strings.
When to use
Use when customizing how makeFormatterStandardSchemaV1 renders terminal issues.
See
- defaultLeafHook — the built-in implementation
- Leaf — the union of terminal issue types
Signature
type LeafHook = (issue: Leaf) => stringmakeFormatterDefault
Creates a Formatter that converts an Issue into a human-readable multi-line string.
When to use
Use when you need to format a SchemaIssue.Issue as error messages for
logging, CLI output, or developer-facing diagnostics.
Details
- Flattens the issue tree into
{ message, path }entries using defaultLeafHook and defaultCheckHook. - Includes reported input in default messages when the node producing the
message has an
inputfield. - Each entry is rendered as
"<message>"or"<message>\n at <path>". - Multiple entries are joined with newlines.
Gotchas
Formatting an issue can disclose input retained with reportInput: true.
Wrapper inputs are not inherited by child messages, and custom messages are
returned unchanged.
See
- makeFormatterStandardSchemaV1 — produces Standard Schema V1 format instead
- Formatter
Signature
declare function makeFormatterDefault(): Formatter<string>Example
(Formatting an issue as a string)
import { SchemaIssue } from "effect"
const formatter = SchemaIssue.makeFormatterDefault()formatter(new SchemaIssue.MissingKey(undefined)) // => "Missing key"makeFormatterStandardSchemaV1
Creates a Formatter that produces a StandardSchemaV1.FailureResult.
When to use
Use when you need schema parse errors in Standard Schema V1 format, optionally customizing leaf or check issue rendering.
Details
- Returns a
Formatter<StandardSchemaV1.FailureResult>. - Each leaf issue is flattened into
{ message, path }entries. Pointerpaths are accumulated to produce full property paths.- Falls back to defaultLeafHook / defaultCheckHook when no hooks are provided.
- Default messages include reported input when the issue that produces the
message has an
inputfield. The returned Standard Schema issues do not receive aninputfield.
Gotchas
Reported input can appear inside the Standard Schema message string even
though it is not exposed as a separate property. Custom hooks control their
complete message and are not modified.
See
- makeFormatterDefault — produces a plain string instead
- LeafHook
- CheckHook
Signature
declare function makeFormatterStandardSchemaV1(options?: { readonly checkHook?: CheckHook; readonly leafHook?: LeafHook;}): Formatter<FailureResult>Example
(Creating a Standard Schema V1 formatter)
import { SchemaIssue } from "effect"
const formatter = SchemaIssue.makeFormatterStandardSchemaV1()formatter(new SchemaIssue.MissingKey(undefined)).issues[0].message // => "Missing key"Guards
Returns true when an issue contains an input reported by the schema parser.
When to use
Use when reading Issue.input, especially when undefined is a valid input
value.
Details
Reported input is stored as an own property. This guard checks for that
property and narrows input from optional to required.
See
- Issue for the complete issue model
Signature
declare function hasInput(issue: Issue): issue is Issue & { readonly input: unknown;}Example
(Reading a reported input)
import { Result, Schema, SchemaIssue } from "effect"
const result = Schema.decodeUnknownResult(Schema.String)(1, { reportInput: true })if (Result.isFailure(result) && SchemaIssue.hasInput(result.failure.issue)) { result.failure.issue.input // => 1}Returns true if the given value is an Issue.
When to use
Use when you need to narrow an unknown value to Issue in error-handling
code, such as distinguishing an Issue from other error types in a catch-all
handler.
Details
- Checks for the internal
TypeIdbrand on the value.
See
Signature
declare function isIssue(u: unknown): u is IssueExample
(Type-guarding an unknown error)
import { SchemaIssue } from "effect"
const issue = new SchemaIssue.MissingKey(undefined)SchemaIssue.isIssue(issue) // => trueSchemaIssue.isIssue("not an issue") // => falseModels
Represents a schema issue produced when a value does not match any member of a union schema.
When to use
Use when you need to inspect which union members were attempted and why each failed.
Details
astis theUnionAST node.issuescontains the per-member failures.
Gotchas
issues is empty when no union member was applicable. In that case, the
default formatter reports the expected type for the union and appends
", got <input>" when input is reported.
See
Signature
declare class AnyOf extends Base { constructor(ast: Union, issues: readonly Array<Issue>, input?: unknown, options?: ParseOptions); readonly _tag: "AnyOf"; readonly ast: Union; readonly issues: readonly Array<Issue>;}Represents a schema issue that groups multiple child issues under a single schema node.
When to use
Use when you need to walk the issue tree for struct/tuple schemas that collect all field errors rather than failing on the first.
Details
issuesis a non-empty readonly array (at least one child).- Formatters flatten
Compositeby recursing into each child.
See
Signature
declare class Composite extends Base { constructor(ast: AST, issues: readonly [Issue, Issue], input?: unknown, options?: ParseOptions); readonly _tag: "Composite"; readonly ast: AST; readonly issues: readonly [Issue, Issue];}Represents a schema issue produced when a schema transformation (encode/decode step) fails.
When to use
Use when you need to inspect failures from Schema.decodeTo / Schema.encodeTo
transformations.
Details
astis the AST node for the transformation that failed.issueis the inner issue describing the failure.
See
Signature
declare class Encoding extends Base { constructor(ast: AST, issue: Issue, input?: unknown, options?: ParseOptions); readonly _tag: "Encoding"; readonly ast: AST; readonly issue: Issue;}Represents a schema issue produced when a schema filter (refinement check) fails.
When to use
Use when you need to inspect a schema issue that records which refinement check rejected the value.
Details
filteris the AST filter node that produced this issue.issueis the inner issue describing the failure reason.
See
Signature
declare class Filter extends Base { constructor(filter: Filter<any>, issue: Issue, input?: unknown, options?: ParseOptions); readonly _tag: "Filter"; readonly filter: Filter<unknown>; readonly issue: Issue;}Example
(Matching a Filter issue)
import { SchemaAST, SchemaIssue } from "effect"
const formatIssue = SchemaIssue.makeFormatterDefault()
function describe(issue: SchemaIssue.Issue): string { if (issue._tag === "Filter") { return `Filter failed: ${formatIssue(issue.issue)}` } return formatIssue(issue)}
const issue = new SchemaIssue.Filter( SchemaAST.isPattern(/^valid$/), new SchemaIssue.InvalidValue())describe(issue) // => `Filter failed: Expected a valid value`Represents a schema issue produced when a forbidden operation is encountered during parsing,
such as an asynchronous Effect running inside Schema.decodeUnknownSync.
When to use
Use when you need to detect that a schema requires async execution but was run synchronously.
Details
annotationsoptionally carries amessagestring.- The default formatter renders this as
"Forbidden operation".
See
- InvalidValue — for value-constraint failures (not operation failures)
Signature
declare class Forbidden extends Base { constructor(annotations: Issue | undefined, input?: unknown, options?: ParseOptions); readonly _tag: "Forbidden"; readonly annotations: Issue | undefined;}Example
(Creating a Forbidden issue)
import { SchemaIssue } from "effect"
const formatIssue = SchemaIssue.makeFormatterDefault()const issue = new SchemaIssue.Forbidden( { message: "async operation not allowed in sync context" })formatIssue(issue) // => "async operation not allowed in sync context"InvalidType
Represents a schema issue produced when the runtime type of the input does not match the type expected by the schema.
When to use
Use when you need to detect basic type mismatches, such as a wrong primitive
or null where an object was expected.
Details
astis the schema node that expected a different type.- The default formatter renders this as
"Expected <type>", adding", got <input>"when the issue reports an input.
See
- InvalidValue — the input has the right type but fails a value constraint
Signature
declare class InvalidType extends Base { constructor(ast: AST, input?: unknown, options?: ParseOptions); readonly _tag: "InvalidType"; readonly ast: AST;}Example
(Formatting a type mismatch)
import { Schema, SchemaIssue } from "effect"
const formatIssue = SchemaIssue.makeFormatterDefault()const issue = new SchemaIssue.InvalidType(Schema.String.ast)formatIssue(issue) // => "Expected string"InvalidValue
Represents a schema issue produced when the input has the correct type but its value violates a constraint (e.g. a string that is too short, a number out of range).
When to use
Use when you need to detect constraint violations from Schema.filter,
Schema.minLength, Schema.greaterThan, or similar checks.
Details
- A
messageannotation is returned unchanged and takes precedence over all other default formatting. - Without
message, anexpectedannotation is formatted as"Expected <expected>", adding", got <input>"when input is reported. - Without either annotation, the default formatter renders
"Expected a valid value", or"Invalid data <input>"when input is reported.
See
- InvalidType — the input has the wrong type entirely
- Filter — composite wrapper when a schema filter produces this issue
Signature
declare class InvalidValue extends Base { constructor(annotations?: Issue, input?: unknown, options?: ParseOptions); readonly _tag: "InvalidValue"; readonly annotations: Issue | undefined;}Example
(Returning InvalidValue from a custom filter)
import { SchemaIssue } from "effect"
const formatIssue = SchemaIssue.makeFormatterDefault()const issue = new SchemaIssue.InvalidValue({ message: "must not be empty" })formatIssue(issue) // => "must not be empty"The root discriminated union of all validation error nodes.
When to use
Use when typing the error channel in Effect<A, Issue, R> results from
schema parsing, or when writing custom formatters or issue-tree walkers.
Details
Every node has a _tag field for pattern-matching. The union includes both
terminal Leaf types and composite types that wrap inner issues:
Filter, Encoding, Pointer, Composite,
AnyOf. Use makeFormatterDefault when a human-readable
representation is needed. When parsing with reportInput: true,
value-bearing issues expose the rejected value through an enumerable input
field. Built-in formatters may include reported input in default messages. This
is not a general sanitization boundary: paths, ASTs, union successes, and
custom annotations or messages are preserved as supplied and remain the
caller's responsibility.
See
Signature
type Issue = Leaf | Filter | Encoding | Pointer | Composite | AnyOfUnion of all terminal (leaf) issue types that have no inner Issue children.
When to use
Use when constraining formatter hooks to only handle terminal nodes or when
pattern matching on the _tag of an issue and only leaf nodes matter.
Details
Members: InvalidType, InvalidValue, MissingKey, UnexpectedKey, Forbidden, OneOf.
See
Signature
type Leaf = InvalidType | InvalidValue | MissingKey | UnexpectedKey | Forbidden | OneOfMissingKey
Represents a schema issue produced when a required key or tuple index is missing from the input.
When to use
Use when you need to detect absent fields in struct/tuple validation.
Details
annotationsmay contain a custommessageMissingKeyfor formatting.
See
- Pointer — wraps this issue with the missing key's path
- UnexpectedKey — the opposite case (extra key present)
Signature
declare class MissingKey extends Base { constructor(annotations: Key<unknown> | undefined); readonly _tag: "MissingKey"; readonly annotations: Key<unknown> | undefined;}Represents a schema issue produced when a value matches multiple members of a union that is configured to allow exactly one match (oneOf mode).
When to use
Use when you need to detect ambiguous union matches when oneOf validation is
enabled.
Details
astis theUnionAST node.successeslists the AST nodes of each member that accepted the input.- The default formatter renders this as
"Expected exactly one member to match", or"Expected exactly one member to match the input <input>"when input is reported.
See
- AnyOf — the opposite: no members matched
Signature
declare class OneOf extends Base { constructor(ast: Union, successes: readonly Array<AST>, input?: unknown, options?: ParseOptions); readonly _tag: "OneOf"; readonly ast: Union; readonly successes: readonly Array<AST>;}Wraps an inner Issue with a property-key path, indicating where in a nested structure the error occurred.
When to use
Use when you need to walk the issue tree to accumulate path segments for error reporting.
Details
pathis an array of property keys (strings, numbers, or symbols).- Formatters concatenate nested
Pointerpaths into a single path like["a"]["b"][0].
See
- Composite — groups multiple issues under one schema node
Signature
declare class Pointer extends Base { constructor(path: readonly Array<PropertyKey>, issue: Issue); readonly _tag: "Pointer"; readonly issue: Issue; readonly path: readonly Array<PropertyKey>;}UnexpectedKey
Represents a schema issue produced when an input object or tuple contains a key/index not declared by the schema.
When to use
Use when you need to detect excess properties during strict struct/tuple validation.
Details
astis the schema that was being validated against.annotationsonastmay contain a custommessageUnexpectedKey.- The default formatter renders this as
"Expected no excess property", or"Unexpected key with value <input>"when the issue reports an input.
See
- MissingKey — the opposite case (required key absent)
- Pointer — wraps this issue with the unexpected key's path
Signature
declare class UnexpectedKey extends Base { constructor(ast: AST, input?: unknown, options?: ParseOptions); readonly _tag: "UnexpectedKey"; readonly ast: AST;}