Missing Key Messages

Avatar of Hemanta SundarayHemanta Sundaray

There’s a specific kind of error that annotate doesn’t cover: a missing key. When a required key is absent from the input object, the error isn’t about the value being wrong (there is no value), it’s about the key itself being missing.

You customize this with annotateKey, not annotate:

schema.ts
import { Schema } from "effect";
const LoginForm = Schema.Struct({
username: Schema.String.annotateKey({
messageMissingKey: "Username is required",
}),
password: Schema.String.annotateKey({
messageMissingKey: "Password is required",
}),
});
const result = Schema.decodeUnknownExit(LoginForm)({});
console.log(String(result));

Output:

Terminal
Failure(Cause([Fail(SchemaError(Username is required
at ["username"]))]))

Without the messageMissingKey annotation, the error would just say “Missing key”, which is technically correct, but not helpful for a user staring at a login form.

annotateKey vs annotate

This is a subtle but important distinction:

  • annotate targets the value. It fires when a value is present but has the wrong type. If someone types “abc” into an age field, annotate({ message: "Age must be a number" }) provides the error.
  • annotateKey targets the key. It fires when the key is entirely absent from the input. If someone leaves the age field blank and the form omits the key entirely, annotateKey({ messageMissingKey: "Age is required" }) provides the error.

You’ll often want both on the same field:

import { Schema } from "effect";
const schema = Schema.Struct({
age: Schema.Number.annotate({ message: "Age must be a number" }) // value is wrong type
.annotateKey({ messageMissingKey: "Age is required" }), // key is missing
});

Now age has a custom message for both error scenarios: missing key and wrong type.

Sign in to save progress

Stay in the loop

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