Error Handling
Ack provides detailed error information when validation fails. This guide explains how to interpret and use these errors.
The SchemaResult
Object
All safeParse()
methods in Ack return a SchemaResult
object. This object encapsulates either the successfully validated data or a SchemaError
.
result.isOk
: Returnstrue
if validation succeeded,false
otherwise.result.isFail
: Returnstrue
if validation failed,false
otherwise.result.getOrThrow()
: Returns the validated data ifisOk
is true, otherwise throws an exception.result.getOrNull()
: Returns the validated data ifisOk
is true, otherwise returnsnull
.result.getError()
: Returns theSchemaError
ifisFail
is true, otherwise throws an exception.result.getOrElse(defaultValue)
: Returns the validated data ifisOk
is true, otherwise returns thedefaultValue
.
import 'package:ack/ack.dart';
final schema = Ack.string().minLength(5);
final result = schema.safeParse('abc');
if (result.isFail) {
final error = result.getError();
print('Validation failed: $error');
// Try to get data (will throw)
try {
result.getOrThrow();
} catch (e) {
print('Caught exception: $e');
}
// Get a default value
final dataOrDefault = result.getOrElse(() => 'default_string');
print('Data or default: $dataOrDefault'); // Output: default_string
}
Understanding SchemaError
The SchemaError
object contains details about the validation failure.
error.name
: A short identifier for the error type (e.g.,'string'
,'object'
).error.errorKey
: The specific error key (e.g.,'schema_constraints_error'
,'schema_nested_error'
).error.value
: The actual value that failed validation.error.schema
: The schema that was being validated against.
final userSchema = Ack.object({
'name': Ack.string(),
'age': Ack.integer().min(18),
'address': Ack.object({
'city': Ack.string()
})
});
final invalidData = {
'name': 'Test',
'age': 15, // Fails min(18)
'address': {
'city': 123 // Fails Ack.string
}
};
final result = userSchema.safeParse(invalidData);
if (result.isFail) {
final error = result.getError();
print('Error Name: ${error.name}'); // Example: 'object'
print('Error Key: ${error.errorKey}'); // Example: 'schema_nested_error'
print('Failed Value: ${error.value}'); // Example: the invalid data
print('Full Error: $error'); // Complete error details
// Note: The exact error structure (especially for nested errors) can vary.
// Sometimes the top-level error might be SchemaNestedError,
// and you might need to inspect its nested errors.
}
Error Types
Ack uses specific error types that inherit from SchemaError
. Each error type provides detailed information about why validation failed.
TypeMismatchError
Occurs when the input value type doesn't match the expected schema type.
final schema = Ack.string();
final result = schema.safeParse(42); // Number instead of string
if (result.isFail) {
final error = result.getError() as TypeMismatchError;
print('Expected: ${error.expectedType}'); // "string"
print('Actual: ${error.actualType}'); // "integer"
print('Error: ${error.message}'); // "Expected string, got integer"
}
SchemaConstraintsError
Occurs when the value violates one or more validation constraints (e.g., minLength
, min
, email
).
final schema = Ack.string().minLength(5).email();
final result = schema.safeParse('abc');
if (result.isFail) {
final error = result.getError() as SchemaConstraintsError;
print('Constraint violations: ${error.constraints.length}');
// Access individual failed constraints
for (final constraintError in error.constraints) {
print('- Constraint: ${constraintError.constraint}');
print('- Message: ${constraintError.message}');
}
}
SchemaNestedError
Occurs when validation fails within nested objects or lists. Contains a list of child errors.
final schema = Ack.object({
'name': Ack.string().minLength(2),
'age': Ack.integer().min(0),
});
final result = schema.safeParse({
'name': 'J', // Too short
'age': -5, // Negative
});
if (result.isFail) {
final error = result.getError() as SchemaNestedError;
print('Nested errors: ${error.errors.length}');
// Recursively inspect nested errors
for (final nestedError in error.errors) {
print('- Field: ${nestedError.name}');
print('- Error: ${nestedError.message}');
}
}
SchemaValidationError
Occurs when custom validation logic added via .refine()
fails.
final schema = Ack.integer().refine(
(value) => value % 2 == 0,
message: 'Must be an even number',
);
final result = schema.safeParse(3);
if (result.isFail) {
final error = result.getError() as SchemaValidationError;
print('Validation error: ${error.message}'); // "Must be an even number"
}
SchemaTransformError
Occurs when a transformation function (from .transform()
) throws an exception.
final schema = Ack.string().transform((value) {
if (value == null) throw Exception('Cannot transform null');
return value.toUpperCase();
});
final result = schema.safeParse(null);
if (result.isFail) {
final error = result.getError() as SchemaTransformError;
print('Transform error: ${error.message}');
print('Cause: ${error.cause}'); // Original exception
}
Working with Error Types
Use pattern matching or type checks to handle different error types:
final result = schema.safeParse(data);
if (result.isFail) {
final error = result.getError();
switch (error) {
case TypeMismatchError():
print('Wrong type: expected ${error.expectedType}');
case SchemaConstraintsError():
print('Failed ${error.constraints.length} constraints');
case SchemaNestedError():
print('Nested validation failed at ${error.errors.length} locations');
case SchemaValidationError():
print('Custom validation failed: ${error.message}');
case SchemaTransformError():
print('Transformation failed: ${error.cause}');
default:
print('Validation failed: ${error.message}');
}
}
Displaying Errors in UI (Flutter Example)
When using Ack with Flutter forms, you can extract the error message for display.
// Inside TextFormField validator
validator: (value) {
final result = someSchema.safeParse(value);
if (result.isFail) {
// Return the error details for the UI
return result.getError().toString();
}
return null; // Return null if valid
}
See the Form Validation Guide for more details.
Custom Error Messages
Built-in constraints provide default error messages. For custom error messages, create custom constraints using the .constrain()
method. See Custom Validation Guide for details.
// Built-in constraints use default messages
final schema = Ack.string().minLength(5);
final result = schema.safeParse('abc');
if (result.isFail) {
final error = result.getError();
print(error.toString()); // Output: validation error details
}
Next Steps
Learn more about related topics:
- Custom Validation: Create custom constraints with tailored error messages
- Flutter Forms: Display validation errors in Flutter form widgets
- Validation Rules: Explore all built-in validation constraints
- Schema Types: Learn about different schema types and their behavior
- Common Recipes: See practical error handling patterns