Error Handling Operators
Operators for throwing and catching errors, providing exception-like error handling in JSONLogic.
Feature flag (Rust crate).
tryandthrowrequire theerror-handlingfeature. Every language binding enables it. See the feature table.
try
Catch errors and provide fallback values.
Syntax:
{ "try": [expression, fallback] }
{ "try": [expression, catch_expression] }
Arguments:
expression- Expression that might throw an errorfallback- Value or expression to use if an error occurs
Returns: Result of expression if successful, or fallback value/expression result if an error occurs.
Context in Catch:
When an error is caught, the catch expression evaluates with the thrown error
object as its context, so its fields are read via var / val:
- A string
throwproduces the error object{ "type": <string> }, so the message is read with{ "var": "type" }. - An object
throw(sourced from data) preserves its own keys, so fields such as{ "var": "code" }or{ "var": "message" }read those keys directly. { "var": "" }returns the entire error object.
Examples:
// Simple fallback value
{ "try": [
{ "/": [10, 0] },
0
]}
// Result: 0 (division by zero caught)
// Expression that succeeds
{ "try": [
{ "+": [1, 2] },
0
]}
// Result: 3 (no error, normal result)
// Catch a string error: the string becomes the error object's "type" field
{ "try": [
{ "throw": "User not found" },
{ "cat": ["Error: ", { "var": "type" }] }
]}
// Result: "Error: User not found"
// Canonical pattern: read a thrown string back via "type"
{ "try": [
{ "throw": "Some error" },
{ "val": "type" }
]}
// Result: "Some error"
// Throw an object sourced from data, then read its fields by key
{ "try": [
{ "throw": { "var": "err" } },
{ "var": "code" }
]}
// Data: { "err": { "code": 404, "message": "User not found" } }
// Result: 404
// Nested try for multiple error sources
{ "try": [
{ "try": [
{ "var": "data.nested.value" },
{ "throw": "nested access failed" }
]},
"default"
]}
Common Patterns
Safe division:
{ "try": [
{ "/": [{ "var": "numerator" }, { "var": "denominator" }] },
0
]}
Safe property access:
{ "try": [
{ "var": "user.profile.settings.theme" },
"default-theme"
]}
Error logging pattern:
{ "try": [
{ "risky_operation": [] },
{ "cat": ["Operation failed: ", { "var": "type" }] }
]}
// For a string throw, the thrown text is in the "type" field. If the operation
// throws a structured object instead, read the relevant key (e.g. "message").
Try it:
throw
Throw an error with optional details.
Syntax:
{ "throw": message }
{ "throw": error_object }
Arguments:
message- Error message string. The string becomes the error object’stypefield, orerror_object- An error object value (sourced from data, or built in templating mode) with arbitrary keys such ascodeandmessage. A multi-key object written inline as a literal does NOT compile in the default engine, because it is parsed as an operator map.
Returns: Never returns normally; throws an error that must be caught by try.
Examples:
// Simple string error (the string lands in the error object's "type" field)
{ "throw": "Something went wrong" }
// Throws the error object { "type": "Something went wrong" }
// Error object sourced from data. A literal multi-key object written inline
// would be parsed as an operator map and fail to compile in the default engine.
{ "throw": { "var": "err" } }
// Data: { "err": { "code": "INVALID_INPUT", "message": "Age must be positive" } }
// Throws an error carrying the object's fields
// Richer error: build the object in your data (or enable templating mode) and
// throw it by reference.
{ "throw": { "var": "validationError" } }
// Data: {
// "validationError": {
// "code": "VALIDATION_ERROR",
// "message": "Invalid email format",
// "field": "email"
// }
// }
// Conditional throw (string form)
{ "if": [
{ "<": [{ "var": "age" }, 0] },
{ "throw": "Age cannot be negative" },
{ "var": "age" }
]}
// Data: { "age": -5 }
// Throws the error object { "type": "Age cannot be negative" }
// Data: { "age": 25 }
// Result: 25
Common Patterns
Validation with throw:
{ "if": [
{ "missing": ["name", "email"] },
{ "throw": "Required fields missing" },
"valid"
]}
Business rule enforcement:
{ "if": [
{ ">": [{ "var": "amount" }, { "var": "balance" }] },
{ "throw": "Amount exceeds balance" },
{ "-": [{ "var": "balance" }, { "var": "amount" }] }
]}
Type validation:
{ "if": [
{ "!==": [{ "type": { "var": "value" } }, "number"] },
{ "throw": "Expected number" },
{ "*": [{ "var": "value" }, 2] }
]}
Try it:
Error Handling Patterns
Graceful Degradation
{ "try": [
{ "var": "user.preferences.language" },
{ "try": [
{ "var": "defaults.language" },
"en"
]}
]}
// Try user preference, then defaults, then hardcoded "en"
Validation Pipeline
{ "try": [
{ "if": [
{ "!": { "var": "input" } },
{ "throw": "Input required" },
{ "if": [
{ "<": [{ "length": { "var": "input" } }, 3] },
{ "throw": "Minimum 3 characters" },
{ "var": "input" }
]}
]},
{ "cat": ["Validation error: ", { "var": "type" }] }
]}
Error Recovery with Retry Logic
{ "try": [
{ "primary_operation": [] },
{ "try": [
{ "fallback_operation": [] },
"all operations failed"
]}
]}
Collecting All Errors
While JSONLogic doesn’t natively support collecting multiple errors, you can structure validations to report all issues:
{
"errors": { "filter": [
[
{ "if": [{ "missing": ["name"] }, "name is required", null] },
{ "if": [{ "missing": ["email"] }, "email is required", null] },
{ "if": [
{ "and": [
{ "!": { "missing": ["email"] } },
{ "!": { "in": ["@", { "var": "email" }] } }
]},
"invalid email format",
null
]}
],
{ "!==": [{ "var": "" }, null] }
]}
}
This returns an array of error messages for all validation failures.