dkuku

dkuku

This is a proposal to make the map key mismatch errors a bit better:
Every time I have a typo It’s very challenging for me even when I understand the error:


I see this in many places - it’s the same in test results. There may be a bit easier because the colors but because the order of keys sometimes changes and the maps are often huge I need to scroll the screen multiple times.
I even changed the test formatter to show only the lines that have ansi sequences but I work on different projects and the formatter needs to be always installed. Similar with errors thrown by dialyzer or hammox.

Showing Posts 1 to 10

mainlymortal

mainlymortal

Something to do with the refunded_at key? One is nil, the other gets a value from somewhere.

cevado

cevado

both clauses expect a :amount key that is not present in the map that is passed as argument.

edit: not sure if your question is about the error or a better way to format this.
in the way you’re using it, it would be better to have a struct or at least use the dot notation to extract the values instead of pattern matching them on function clause:

def build(something) do
  created_at = something.created_at
  ...
end
dkuku

dkuku OP

@cevado I mean better formatting. I updated the op mentioning this.

al2o3cr

al2o3cr

Pattern-matching on huge maps is, IMO, hard to read in code - and correspondingly harder to read in test failures.

For instance, the error message you posted suggests there are two build heads:

def build(%{
  created_at: created_at,
  refunded_at: nil,
  id: job_id,
  provider_id: provider_id,
  sale_id: sale_id,
  customer_id: customer_id,
  appointment_id: appointment_id,
  amount: total_gross,
  type: fee_type,
  currency_code: currency_code
}) do
...
end

def build(%{
  created_at: created_at,
  refunded_at: refunded_at,
  id: job_id,
  provider_id: provider_id,
  sale_id: sale_id,
  customer_id: customer_id,
  appointment_id: appointment_id,
  amount: total_gross,
  type: fee_type,
  currency_code: currency_code
}) do
...t=
end

Sharp-eyed readers may spot that refunded_at is matched to nil in one and bound to refunded_at in the other, but it’s the same kind of difficulty you’re highlighting with the test failure message.

+1 for @cevado’s suggestion - writing this as:

def build(args) do
  total_gross = args.amount
  ...
end

would make the test in your original post fail with a KeyError complaining explicitly about amount not being present in args.

dkuku

dkuku OP

This is just one example and it’s not only pattern matching related. In tests or dialyzer errors the comparison is between 2 maps that are very similar and you may get it randomly because something started to fail. This was always causing issues for me and I wanted to raise it. I’m happy to implement it when we have a good idea how to handle this.

cevado

cevado

this specific formatting only happens on function clause errors, i don’t think it can be better formatted.
for tests if you’re using ExUnit it shows only the diff with it highlighted if you’re asserting a pattern match. my suggestion in that case is to do something like:

expected_response = %{...}
...
{:ok, response} = function_testing(...)

assert expected_response = response
dkuku

dkuku OP

We have a big elixir codebase and sometimes the expected response is 100 lines long. I know it shouldn’t be like that but it is how it is.

LostKobrakai

LostKobrakai

At this point I’d suggest refactoring assertions to work on smaller subsets instead of comparing the whole response at once:

assert {:ok, response} = function_testing(…)

assert something == response.a
assert something_else == response.b
assert something_else_again == response.c
dkuku

dkuku OP

I need to try how a llm will handle the refactor, otherwise it may take a lifetime :smiley:

sodapopcan

sodapopcan

Having not used LLMs myself, if that doesn’t work you might have some luck with Sourceror depending on how consistent your map assertions are.

Where Next? Top

Trending in Proposals: Ideas Top

Other Trending Topics Top

GenericJam
Edit: 2026 May 15 - This post is archived. Mob is alive!! Main docs: mob v0.7.11 — Documentation A bit of explanation for the slightly c...
New
JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
garrison
Hobbes is a low-level distributed database for the Elixir programming language. Hobbes provides a simple, safe, and scalable storage lay...
New
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
mhanberg
Hi everyone! The first release candidate for the Expert language server project is now available! We’ve published a press release detai...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews