Reporting Multiple Errors

Avatar of Hemanta SundarayHemanta Sundaray

By default, Schema stops at the first error it encounters. This is called “fail-fast” behavior, and it’s the default for a good reason: it’s faster. If you’re processing millions of records in a pipeline, you don’t want to spend time finding every error in a record that’s already known to be invalid. You just want to skip it and move on.

But there’s a big class of use cases where fail-fast is exactly wrong: form validation. When a user submits a form with three errors, you don’t want to show them one error, wait for them to fix it, then show them the next one, then wait again. You want to show all three errors at once so they can fix everything in one pass.

Pass { errors: "all" } as the second argument to any decode function to collect every issue in a single pass:

schema.ts
import { Schema } from "effect";
const UserSchema = Schema.Struct({
name: Schema.String,
age: Schema.Number,
email: Schema.String,
});
const result = Schema.decodeUnknownExit(UserSchema)(
{ name: 42, age: "not a number" },
{ errors: "all" },
);
console.log(String(result));

Output:

Terminal
Failure(Cause([Fail(SchemaError(Expected string, got 42
at ["name"]
Expected number, got "not a number"
at ["age"]
Missing key
at ["email"]))]))

All three errors are reported: email is missing, age has the wrong type, and name has the wrong type. Without { errors: "all" }, you’d only see the first error that UserSchema encountered.

Setting errros: "all" at the Schema Level

Passing { errors: "all" } on every decode call gets repetitive. If you know a schema will always be used for form validation, you can bake the option into the schema itself using .annotate:

schema.ts
import { Schema } from "effect";
const UserSchema = Schema.Struct({
name: Schema.String,
age: Schema.Number,
email: Schema.String,
}).annotate({ parseOptions: { errors: "all" } });
// No need to pass { errors: "all" } — it's already set
const result = Schema.decodeUnknownExit(UserSchema)({
name: 42,
age: "not a number",
});
console.log(String(result));

This way, every decode call on this schema reports all errors by default, without the caller needing to remember to pass the option.

Sign in to save progress

Stay in the loop

Get notified when new chapters are added and when this course is complete.