Validate ops

v0.1.4

Validate ops check a value and report an error when it fails. This page lists the 65 built-in validate ops. You write them in the validate(...) group of a derive string, as in "validate(string, max_len=80)". A failing op adds an error whose action is the op's name, with the exceptions listed under Failure actions.

Types

Each of these passes when the value is of the named kind. The error message reads The <field> field must be <op>.

OpPasses when the value is
stringA binary.
integerAn integer.
floatA float.
numberAn integer or a float.
booleantrue or false.
atomAn atom.
bitstringA bitstring.
listA list.
mapA map. A struct is a map.
tupleA tuple.
structA struct.
exceptionAn exception struct.
functionA function.
pidA pid.
portA port.
referenceA reference.
nil_valuenil.
not_nil_valueAnything but nil.

A field that is nil is skipped before any op runs, apart from sanitize(default_when_nil=...), so nil_value and not_nil_value only see values that are not nil. A struct in the input stays a struct inside builder/1, so struct and exception see it. See How the builder works.

Other structures

OpPasses when the value is
queueAn Erlang queue, as :queue.is_queue/1 decides.
recordA non-empty tuple whose first element is an atom.
record=tagA tuple like the above whose first element is tag. record=user accepts {:user, "Alice", 30}.
rangeA Range.

Emptiness and size

OpPasses when the value is
not_emptyA string, list or map that is not empty. Any other kind of value fails.
not_empty_stringA string that is not empty.
not_flatten_emptyA list that still has an item after List.flatten/1.
not_flatten_empty_itemA list that still has an item after flattening and has no [] as a direct item.
max_len=NAt most N. A string is measured by String.length/1, a list by length/1, an integer or float by its value, and a range by its last element.
min_len=NAt least N, measured the same way. A range is measured by its first element.

Text and format

OpPasses when the value is
email_rA string that matches ^[A-Za-z0-9\._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}$. It makes no network call.
emailAn address that EmailChecker.valid?/1 accepts. It can query DNS. Needs the email_checker package.
urlA string with a scheme and a host, where the scheme is http or https, the port is 80 or 443 (the default of the scheme counts), and :inet.gethostbyname/1 resolves the host. It makes a lookup.
tellA phone number such as +4930123456, without spaces, checked as a tel: URL. Needs ex_url.
tell=codeA phone number whose country calling code is code. tell=49 accepts +4930123456. Needs ex_url and ex_phone_number.
geo_urlLatitude and longitude such as 48.198634,-16.371648. A value that already starts with geo: fails. Needs ex_url.
locationThe same as geo_url, with spaces removed first, so 48.198634, -16.371648 passes. Optional parts such as ;crs=wgs84 are accepted. Needs ex_url.
uuidA string of 8-4-4-4-12 hexadecimal digits, in any case.
ipv4Four dot-separated integers from 0 to 255.
ipv6An IPv6 address. It must contain a colon, so an IPv4 address fails.
ipAn IPv4 or IPv6 address, as :inet.parse_address/1 decides.
regex=patternA string that matches the pattern.
usernameA string of 5 to 34 characters that starts with a letter and holds only letters, digits and underscores.
full_nameA string of lower-case letters a to z and spaces that does not start with a space.
slugA string that matches ^[a-z0-9]+(?:-[a-z0-9]+)*$.
hostnameA string of at most 253 bytes with no underscore that :inet_parse.domain/1 accepts.
port_numberAn integer from 1 to 65535.
hex_colorA string of # and 3 or 6 hexadecimal digits.
semverA string that Version.parse/1 accepts. 1.2.3-rc.1 passes and 1.2 fails.
language_codeA string of 2 or 3 letters, followed by optional - parts of 2 to 8 letters or digits, such as en, en-US or zh-Hant.
string_booleanThe string "true" or "false".
string_floatA string that String.to_float/1 reads completely. "1.5" passes. "1" and "1.5abc" fail.
string_integerA string that String.to_integer/1 reads completely. "15" passes and "1.5" fails.
some_string_floatA string that starts with a float, as Float.parse/1 reads it. "1.5abc" passes and "abc" fails.
some_string_integerA string that starts with an integer, as Integer.parse/1 reads it.

Dates and times

OpPasses when the value is
datetimeAn ISO 8601 string with an offset that DateTime.from_iso8601/1 accepts. A DateTime struct fails.
dateAn ISO 8601 date string such as 2026-05-14. A Date struct fails.
utc_datetimeA DateTime struct, or an ISO 8601 string with an offset.
naive_datetimeA NaiveDateTime struct, or an ISO 8601 string.
date_structA Date struct, or an ISO 8601 date string.
time_structA Time struct, or an ISO 8601 time string such as 10:00:00.
past_datetimeA DateTime, NaiveDateTime or Date struct, or an ISO 8601 string of one of those kinds, at or before the current time.
future_datetimeThe same kinds as past_datetime, at or after the current time.

Choices and combinators

OpPasses when the value is
enum=Type[a::b]One of the listed values, of that type. See Derive string syntax for the types.
equal=NEqual to the integer N, compared with ===.
equal=Type::valueEqual to a value of that type: equal=Float::1.5, equal=String::hello, equal=Atom::name, equal=Map::%{a: 1}, equal=Tuple::{:a, 1}. See Derive string syntax.
custom=[Module, function]A value for which Module.function(value) returns true. Any other result, or an exception, fails.
either=[ops]A value that passes at least one inner op.
optional=[ops]nil, or a value that passes all inner ops.
each=[ops]A list whose every item passes all inner ops. A failing item adds errors with an __index__ key.

Failure actions

  • An op that is given a kind of value it does not handle reports the action type for these ops: min_len, max_len, regex, date, location, not_flatten_empty and not_flatten_empty_item. Any other op reports its own name.
  • An op name that nothing defines reports the action type with the message Unexpected type error in <field> field.
  • email, tell, geo_url and location need an optional package. The package is looked up when the op runs, so the order of your dependencies does not matter. Without the package the op fails with its own name as the action, and the message names the package to add, such as {:ex_url, "~> 2.0"}.
  • When a validate op is the first in its group, the value it returns replaces the field's value. location and geo_url return the geo: URL, and enum returns the matching item of its list, so 2 against Float[1.5::2.0] becomes 2.0.