jvoegele

jvoegele

After a good run of 0.x releases, Errata 1.0.0 is here — the first stable, production-ready release. The public API is now covered by Semantic Versioning, so you can depend on it with confidence.

Errata was first announced here; this thread is the 1.0 milestone, with the full picture of what the library does now.

What is Errata?

Errata is a library for structured, named error handling. In Elixir we usually signal failure either by returning {:error, reason} or by raising an exception — but an ad-hoc reason atom (or worse, a string) carries no context once it’s far from where it was created, and plain exceptions lack a common shape to build logging and reporting around.

Errata replaces both with named error types that share a consistent structure and carry full context about what went wrong and where. The same type works as a raise-able exception and as a value you return in an {:error, _} tuple.

Define an error type in one line

defmodule MyApp.Orders.PaymentDeclined do
  use Errata.DomainError,
    default_message: "the payment was declined",
    reasons: [:insufficient_funds, :fraud_suspected, :card_expired]
end

That generates an exception struct, the Errata.Error behaviour, and String.Chars + Jason.Encoder implementations. Errors come in three kinds — domain, infrastructure, and general — so boundary code can treat business errors differently from system failures.

Every error carries its context

Each Errata error has a well-defined shape:

  • message — a human-readable description
  • reason — an atom that classifies the error (optionally a declared, validated set)
  • context — arbitrary metadata captured at the site of the error
  • cause — a lower-level error this one wrapped, preserving the original
  • env — the module, function, file, line, and stacktrace where it was created

Because all of that travels with the error, you can create it deep in your code and then log, report, or render it to JSON at a boundary without losing the information needed to interpret it. This pays off especially in with expressions: when each error is a structured type that carries its own context, you can drop the else clause and let errors propagate to a boundary where they’re handled — no loss of detail.

At a boundary, it all comes together

# A Phoenix fallback controller that handles *any* Errata error uniformly:
def call(conn, {:error, error}) when Errata.is_error(error) do
  Errata.report(error, log: :warning)   # structured Logger metadata + an [:errata, :error] telemetry event

  conn
  |> put_status(Errata.http_status(error))         # :domain → 422, :infrastructure → 503, :general → 500
  |> json(%{error: Errata.display_message(error)}) # the user-facing message, distinct from the dev message
end

A few of the things that round out 1.0:

  • Rich creation — Errata.create/2 builds an error of any type while capturing the call site, and wrap/2 translates a lower-level failure into one of your own error types without losing the original (rescue e -> PaymentGateway.wrap(e, stacktrace: __STACKTRACE__, reason: :timeout)).
  • Context enrichment — put_context/3 and merge_context/2 add to an error’s context as it propagates up a with chain, without rebuilding the struct.
  • Declared reasons — enumerate a type’s valid reasons and have them validated, with a reason/0 type generated into your docs.
  • Error reporting — Errata.log/2 attaches the error’s fields as structured Logger metadata; Errata.report/2 emits a [:errata, :error] telemetry event. It’s a vendor-neutral seam: attach a handler that forwards to Sentry, a metrics backend, or wherever — Errata stays out of the integration business.
  • HTTP status mapping — an overridable http_status/1 on every error type, defaulting off its kind.
  • Cause chaining — cause/1, root_cause/1, and format_chain/1 for following and rendering a chain of wrapped errors.
  • Classification guards — is_error/1, is_domain_error/1, and is_infrastructure_error/1 for branching at boundaries.

Install

{:errata, "~> 1.0"}

There’s plenty more in the docs — choosing between a distinct error type and a :reason, the domain/infrastructure/general distinction, handling errors with the custom guards, and serialization to JSON.

Thanks to everyone who’s tried Errata and shared feedback along the way; it genuinely shaped the road to 1.0. Feedback and contributions are always welcome.

Links

Showing Posts 1 to 2

cmo

cmo

Can you make Jason optional and implement JSON.Encoder now that we have built in JSON support?

jvoegele

jvoegele OP

Thanks for the suggestion @cmo!

I’ve released 1.1.0 to address this. On Elixir 1.18+ every Errata error type now implements the built-in JSON.Encoder protocol, so JSON.encode!(error) works with no third-party dependencies, and jason becomes an optional dependency. If Jason is present you still get a Jason.Encoder implementation exactly as before, so nothing breaks for existing users — both backends produce the same JSON shape. Projects on 1.18+ that don’t otherwise use Jason can simply drop it.

— All posts loaded —

Where Next? Top

Trending in News & Updates Top

woylie
Doggo 0.18.3 has been released. Added tabs: Add a disabled attribute to the :panel slot. A disabled tab can be focused with the arrow k...
New
mat-hek
Popcorn, the library that runs Elixir code in the browser, is now stable :popcorn: This is possible because it now builds on a very stab...
New
GenericJam
Mob 0.9.18 has been released. Added anchor: "bottom" on :scroll, for chat logs (MOB-481). The scroll opens at the end of its content. ...
New
danj
Some root certs are compromised, updates are needed to maintain TLS security. As reported by Mozilla the eMudhra intermediate CA privat...
New
schainks
SystemOneClient v0.2.0 has been released. Added provider: :openai for OpenAI’s Decisions API (POST /v1/decisions, default model gpt-6-...
New
woylie
Doggo 0.18.4 has been released. Fixed menu: Run phx-click-away bindings when an item is chosen. menu, menu_bar: Choose the focused item...
New
woylie
Doggo 0.18.2, 0.18.1 and 0.18.0 have been released. Fixed alert_dialog, modal: Show an open dialog as a modal again when a patch moves ...
New

Other Trending Topics Top

dominicletz
Hey there, I haven’t seen a list of useful Elixir specific skills for the popular AI tools yet so I’m starting one here with my first. ...
New
mudasobwa
I fully migrated to my own harness from Anthropic/Gemini and I think it’s time to share it. Welcome DSH, the DeepSeek Harness, fully writ...
New
KristerV
Hey. Is there anyone here who creates agents in their apps? Not talking about using agents, but creating them. I’m finding it pretty diff...
New
OndrejValenta
(I just needed to vent somewhere and LinkedIn is full of hope, or hype, I’m not sure which exactly) AI dream has many faces, but general...
New
webofbits
With AI doing more of the implementation work, I’ve been wondering how much coding I should deliberately keep doing myself. My main conc...
#ai
New
kip
In 2021 I started a new library called Tempo with the objective of modelling time as a set of intervals - not as instants. In 2022 I gave...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews