Error Handling

Ack provides detailed error information when validation fails. This guide explains how to interpret and use these errors.

The SchemaResult Object

All validate() methods in Ack return a SchemaResult object. This object encapsulates either the successfully validated data or a SchemaError.

  • result.isOk: Returns true if validation succeeded, false otherwise.
  • result.isFail: Returns true if validation failed, false otherwise.
  • result.getOrThrow(): Returns the validated data if isOk is true, otherwise throws an exception.
  • result.getOrNull(): Returns the validated data if isOk is true, otherwise returns null.
  • result.getError(): Returns the SchemaError if isFail is true, otherwise throws an exception.
  • result.getOrElse(defaultValue): Returns the validated data if isOk is true, otherwise returns the defaultValue.
import 'package:ack/ack.dart';

final schema = Ack.string.minLength(5);
final result = schema.validate('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.int.min(18),
  'address': Ack.object({
    'city': Ack.string
  })
}, required: ['name', 'age']);

final invalidData = {
  'name': 'Test',
  'age': 15, // Fails min(18)
  'address': {
    'city': 123 // Fails Ack.string
  }
};

final result = userSchema.validate(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:

  • SchemaConstraintsError: The data violates one or more constraints (e.g., minLength, min, pattern). Contains a list of constraints.
  • SchemaNestedError: An error occurred within a nested object or list. Contains a list of errors.
  • SchemaUnknownError: An unexpected error occurred during validation.
final error = result.getError();

if (error is SchemaConstraintsError) {
  print('Constraint violation: $error');
  // You can access individual failed constraints
  for (final constraint in error.constraints) {
    print('- Failed constraint: ${constraint.constraint}, Message: ${constraint.message}');
  }
} else if (error is SchemaNestedError) {
  print('Nested error with ${error.errors.length} errors');
  // Recursively inspect error.errors
  for (final nestedError in error.errors) {
    print('- Nested: $nestedError');
  }
}

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.validate(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.validate('abc');
if (result.isFail) {
  final error = result.getError() as SchemaConstraintsError;
  print(error.constraints.first.message); // Output: "Too short, min 5 characters"
}