Sinter.Error (Sinter v0.0.1)

View Source

Structured error representation for Sinter validation errors.

This module provides a consistent way to represent validation errors throughout Sinter, including path information for nested data structures and machine-readable error codes.

Summary

Functions

Filters errors by error code.

Formats an error into a human-readable string.

Formats multiple errors into a readable string.

Groups errors by their error code.

Groups errors by their path for easier processing.

Creates a new validation error.

Summarizes validation errors into a report.

Converts an error to a map representation.

Converts multiple errors to map representations.

Creates a new error with additional context information.

Adds LLM debugging context to a validation error.

Types

t()

@type t() :: %Sinter.Error{
  code: atom(),
  context: map() | nil,
  message: String.t(),
  path: [atom() | String.t() | integer()]
}

Functions

filter_by_code(errors, code)

@spec filter_by_code([t()], atom()) :: [t()]

Filters errors by error code.

Examples

iex> errors = [
...>   Sinter.Error.new([:name], :required, "field is required"),
...>   Sinter.Error.new([:age], :type, "expected integer")
...> ]
iex> Sinter.Error.filter_by_code(errors, :required)
[%Sinter.Error{path: [:name], code: :required, ...}]

format(error, opts \\ [])

@spec format(
  t(),
  keyword()
) :: String.t()

Formats an error into a human-readable string.

Parameters

  • error - The error to format
  • opts - Formatting options

Options

  • :include_path - Include the path in the formatted message (default: true)
  • :path_separator - Separator for path elements (default: ".")

Examples

iex> error = %Sinter.Error{
...>   path: [:user, :email],
...>   code: :format,
...>   message: "invalid email format"
...> }
iex> Sinter.Error.format(error)
"user.email: invalid email format"

iex> Sinter.Error.format(error, include_path: false)
"invalid email format"

format_errors(errors, opts \\ [])

@spec format_errors(
  [t()],
  keyword()
) :: String.t()

Formats multiple errors into a readable string.

Examples

iex> errors = [
...>   Sinter.Error.new([:name], :required, "field is required"),
...>   Sinter.Error.new([:age], :type, "expected integer")
...> ]
iex> Sinter.Error.format_errors(errors)
"name: field is required\nage: expected integer"

group_by_code(errors)

@spec group_by_code([t()]) :: %{required(atom()) => [t()]}

Groups errors by their error code.

Examples

iex> errors = [
...>   Sinter.Error.new([:name], :required, "field is required"),
...>   Sinter.Error.new([:email], :required, "field is required"),
...>   Sinter.Error.new([:age], :type, "expected integer")
...> ]
iex> Sinter.Error.group_by_code(errors)
%{
  required: [
    %Sinter.Error{path: [:name], ...},
    %Sinter.Error{path: [:email], ...}
  ],
  type: [
    %Sinter.Error{path: [:age], ...}
  ]
}

group_by_path(errors)

@spec group_by_path([t()]) :: %{required([atom() | String.t() | integer()]) => [t()]}

Groups errors by their path for easier processing.

Examples

iex> errors = [
...>   Sinter.Error.new([:user, :name], :required, "field is required"),
...>   Sinter.Error.new([:user, :name], :min_length, "too short"),
...>   Sinter.Error.new([:user, :email], :format, "invalid format")
...> ]
iex> Sinter.Error.group_by_path(errors)
%{
  [:user, :name] => [
    %Sinter.Error{code: :required, ...},
    %Sinter.Error{code: :min_length, ...}
  ],
  [:user, :email] => [
    %Sinter.Error{code: :format, ...}
  ]
}

new(path, code, message, context \\ nil)

@spec new(
  [atom() | String.t() | integer()] | atom() | String.t(),
  atom(),
  String.t(),
  map() | nil
) :: t()

Creates a new validation error.

Parameters

  • path - Path to the field that caused the error
  • code - Machine-readable error code
  • message - Human-readable error message
  • context - Optional additional context information

Examples

iex> Sinter.Error.new([:user, :email], :format, "invalid email format")
%Sinter.Error{
  path: [:user, :email],
  code: :format,
  message: "invalid email format",
  context: nil
}

iex> Sinter.Error.new(:name, :required, "field is required")
%Sinter.Error{path: [:name], code: :required, message: "field is required"}

summarize(errors)

@spec summarize([t()]) :: map()

Summarizes validation errors into a report.

Examples

iex> errors = [
...>   Sinter.Error.new([:name], :required, "field is required"),
...>   Sinter.Error.new([:age], :type, "expected integer"),
...>   Sinter.Error.new([:email], :format, "invalid email format")
...> ]
iex> Sinter.Error.summarize(errors)
%{
  total_errors: 3,
  error_codes: [:required, :type, :format],
  affected_paths: [[:name], [:age], [:email]],
  by_code: %{
    required: 1,
    type: 1,
    format: 1
  }
}

to_map(error)

@spec to_map(t()) :: map()

Converts an error to a map representation.

Useful for JSON serialization or API responses.

Examples

iex> error = Sinter.Error.new([:user, :email], :format, "invalid email format")
iex> Sinter.Error.to_map(error)
%{
  "path" => ["user", "email"],
  "code" => "format",
  "message" => "invalid email format"
}

to_maps(errors)

@spec to_maps([t()]) :: [map()]

Converts multiple errors to map representations.

Examples

iex> errors = [
...>   Sinter.Error.new([:name], :required, "field is required"),
...>   Sinter.Error.new([:age], :type, "expected integer")
...> ]
iex> Sinter.Error.to_maps(errors)
[
  %{"path" => ["name"], "code" => "required", "message" => "field is required"},
  %{"path" => ["age"], "code" => "type", "message" => "expected integer"}
]

with_context(path, code, message, context)

@spec with_context(
  [atom() | String.t() | integer()] | atom() | String.t(),
  atom(),
  String.t(),
  map()
) :: t()

Creates a new error with additional context information.

Examples

iex> context = %{expected: "string", actual: "integer", value: 42}
iex> Sinter.Error.with_context([:age], :type, "expected string", context)
%Sinter.Error{
  path: [:age],
  code: :type,
  message: "expected string",
  context: %{expected: "string", actual: "integer", value: 42}
}

with_llm_context(error, llm_response, prompt)

@spec with_llm_context(t(), term(), String.t()) :: t()

Adds LLM debugging context to a validation error.

This function enhances errors with information about the LLM response and original prompt, making it easier to debug validation failures in DSPEx programs.

Parameters

  • error - The original validation error
  • llm_response - The raw response from the LLM
  • prompt - The original prompt sent to the LLM

Returns

  • Enhanced error with LLM context information

Examples

iex> error = Sinter.Error.new([:name], :required, "field is required")
iex> llm_response = %{"age" => 30}  # missing name field
iex> prompt = "Generate a user profile with name and age"
iex> enhanced = Sinter.Error.with_llm_context(error, llm_response, prompt)
iex> enhanced.context.llm_response
%{"age" => 30}
iex> enhanced.context.prompt
"Generate a user profile with name and age"