![]()
The current "boxed" format for errors looks cool, but imho it's not very practical:
|It looks ugly if you resize the window:
![]()
Less importantly:
│ FAIL ├─ ───I propose going for a simpler format, such as:
# ❌ FAIL ────────────────────────────────────────────
# /mnt/exercism-iteration/reverse-string-test.roc:60:1
# ────────────────────────────────────────────────────
expect {
result = reverse("ผู้เขียนโปรแกรม")
result == "มรกแรปโนยขีเผู้"
}
This output can be directly copy/pasted to a Roc file, including the header (thanks to the #). It also takes up 30% less horizontal and vertical space (in this example), resizing the window will work as expected, and I find it easier to parse visually.
that's cool! :smiley:
Glad you like the idea! :blush:
Another benefit is that you get Roc syntax highlighting if you copy/paste the error to a GitHub issue. :art:
I wonder what that same design would look like in other error messages
Agreed, I'll look into that
Here's a proposal for each error/warning format.
┌──────┐
│ FAIL ├─ ───────────────────────────────────────────────────────────────────┐
└┬─────┘ │
│ │
│ expect { │
│ result = reverse("ผู้เขียนโปรแกรม") │
│ result == "มรกแรปโนยขีเผู้" │
│ } │
│ │
└────────────────────── /mnt/exercism-iteration/reverse-string-test.roc:60:1 ┘
# ❌ FAIL ────────────────────────────────────────────
# /mnt/exercism-iteration/reverse-string-test.roc:60:1
# ────────────────────────────────────────────────────
expect {
result = reverse("ผู้เขียนโปรแกรม")
result == "มรกแรปโนยขีเผู้"
}
┌───────────────┐
│ TYPE MISMATCH ├─ This string literal is being used where a non-string ──────┐
└┬──────────────┘ type is needed. │
│ │
│ "hello world", │
│ ‾‾‾‾‾‾‾‾‾‾‾‾‾ │
└──────────────────────────────────────── can_list_multiline_mismatch.md:3:7 ┘
The type was determined to be:
Dec
# ❌ TYPE MISMATCH ───────────────────────────────────
# can_list_multiline_mismatch.md:3:7
# This string literal is being used where a non-string type is needed.
# The type was determined to be:
# Dec
# ────────────────────────────────────────────────────
"hello world",
^^^^^^^^^^^^^
┌───────────────┐
│ TYPE MISMATCH ├─ This `if` condition has different return types in branches. ┐
└┬──────────────┘ │
│ │
│ if cond │
│ "hello" │
│ ‾‾‾‾‾‾‾ │
│ else │
│ 123 │
│ ─── │
└─────────────────────────────────────────────── examples/branches.roc:10:5 ──┘
# ❌ TYPE MISMATCH ────────────────────────────────────
# examples/branches.roc:10:5
# This `if` condition has different return types in branches.
# ─────────────────────────────────────────────────────
if cond
"hello"
^^^^^^^
else
123
^^^
┌──────────────────────┐
│ DUPLICATE DEFINITION ├─ The name `x` is being redeclared here. ─────────────┐
└┬─────────────────────┘ │
│ │
│ x = 20 # Should shadow top-level x │
│ ‾ │
└────────────────────────────────────────────────── can_basic_scoping.md:7:5 ┘
In this scope, `x` was already defined here:
┌───────────────────────────────────────────────────────┐
2 │ x = 5 │
│ ‾ │
└───────────────────────────── can_basic_scoping.md:2:1 ┘
# ❌ DUPLICATE DEFINITION ─────────────────────────────
# can_basic_scoping.md:7:5
# The name `x` is being redeclared here.
# ─────────────────────────────────────────────────────
x = 20 # Should shadow top-level x
^
# ℹ️ DETAILS ────────────────────
# can_basic_scoping.md:2:1
# In this scope, `x` was already defined here:
# ───────────────────────────────
x = 5
^
┌─────────────────┐
│ UNUSED VARIABLE ├─ Variable `unused_val` is defined but never used. ────┐
└┬────────────────┘ │
│ │
│ unused_val = 42 │
│ ‾‾‾‾‾‾‾‾‾‾ │
└───────────────────────────────────────────────────────── main.roc:12:5 ┘
# ⚠️ UNUSED VARIABLE ──────────────────────────────────
# main.roc:12:5
# Variable `unused_val` is defined but never used.
# ─────────────────────────────────────────────────────
unused_val = 42
^^^^^^^^^^
FILE NOT FOUND
I could not find the file `missing_module.roc`.
# ❌ FILE NOT FOUND ───────────────────────────────────
# I could not find the file `missing_module.roc`.
# ─────────────────────────────────────────────────────
After more thought, I'm not sure we should make the error headers Roc comments: it's got its upsides, but it might make it harder to parse the errors, especially if the user's code contains comments. Perhaps the error headers should remain boxes, but more concise. However, the user's code should remain without boxes, for example:
┌─ ❌ DUPLICATE DEFINITION
│ The name `x` is being redeclared here.
└─ can_basic_scoping.md:7:5
x = 20 # Should shadow top-level x
^
┌─ ℹ️ DETAILS
│ In this scope, `x` was already defined here:
└─ can_basic_scoping.md:2:1
x = 5
^
I removed the right part of the box for many of the same reasons as for the code, e.g., resizing a full box would be ugly.
+1 for not having headers as comments
i like elm-style, but mb not indented for easy copy/paste
Something like this?
![]()
yeah! i always found the ——- separators clear to distinguish between errors, when scanning, and felt the sequence of:
title, 1-like summary, code, types, hints
as telling a clear story within a single error
Yes, it looks simple and clear, indeed. Would you get rid of the line number and indentation for the code? I like that Roc's error messages have a link containing the file name, line number, and horizontal position, so I can click on the link and arrive straight at the right location in my editor.
yeah, maybe we keep the line/col in the title line, eg TITLE——-—-file.roc:6:7 ?
Something like this?
![]()
Actually the light gray is hard to read, it looks nicer in white, imo:
![]()
And here's an error:
![]()
I like the last examples. I'd just modify the hints so that the DETAILS sections doesn't have a full line which makes me think it's its own separate diagnostic item, not that it belongs to the one above it.
I get that you now have to put the file link somewhere else, but imho its not worth it for the consistency. Either we put the link somewhere else for hints or we put it elsewhere for every diagnostic item.
Love these improvements! +1 to Norbert's suggestion of only using the horizontal lines between different errors/diagonostics so those are super-easy to distinguish.
And +1 to the idea of not using the light grey, for better contrast.
Cool, I'm on it.
I've submitted PR #10643 but I'll update it in a few minutes to avoid the separate DETAILS section.
How about this?
![]()
I like the visual cleanup!
I'm not sure though using emojis is a good idea; they tend to look vastly different depending on OS/Font, and judging from the screenshots I'd say they take up too much visual attention.
What about lightweight unicode symbols like ‼, ℹ or 🛈, maybe framing it like [] to regain lost visual weight, and a Σ to prefix the stats line? To give some ideas for what it could look like (ghostty, don't know the font):
![]()
Looks beautiful!
I know this goes against the copyability goal, but I do think putting the line number in front of the error line like Elm does helps me visually, because it makes the error look more like a snippet from my editor.
In addition I think the column number doesn't add much for me given there's also the highlighted snippet of code in the error, which I think communicates the location of the error on the line better. I do think the column number makes a ton of sense in compiler output intended for programmatic reading by tools though.
BTW ^^ (my firefox on macos)
![]()
yeah, i guess what are the concrete use-cases for wanting to copy/paste the code from an error snippet?
i also agree the line numbers in the code snippet are visually orienting & imo look nice
Matthieu Pizenberg said:
BTW ^^ (my firefox on macos)
Ah, similar for me on mobile :sweat_smile:
Great points, thanks. I love the ghostty style without emojis, it looks beautiful with the text colors too. One detail is that I prefer to make the dashes go to the end of the line, as in Elm (but with a maximum width of 120 characters).
I played around with the new format yesterday, and I realized that the main benefit of dropping the boxes is getting rid of the pipes on the right, because I frequently resize my window and the pipes end up on the next line when shrinking the width. This happens as well with the dashes in the new design, but much less often because of the 120 char limit, and it's less annoying because it mostly affects the dashed lines. Not having the right pipes anymore feels so much better!
After more thought, the copy/paste benefit is secondary. I personally quite like the current clean look without the line numbers, but if most people prefer showing line numbers, I'm happy to add them.
I like having the horizontal position in the link because I can Cmd-click and arrive straight at the right position. It's useful particularly for long lines and I don't think it hurts much visually, do you?
I'll make these changes today.
/poll Show line numbers on the left of the code?
Yes
No
I like both
/poll File location format?
Foo.roc:51:64
Foo.roc:51
Foo.roc
I included the Foo.roc option for completeness, but I really don't recommend it because it doesn't let the user click the link to go to the right line.
I updated PR #10643. I went with the ghostty style, without line numbers for now. Here's what it looks like:
![]()
![]()
I tried the light purple color for the last line, but the mix of colors was too much:
![]()
This is why I went with white instead.
I like it :)
here's a related option: use ✘ for errors and ⚠︎ for warnings without brackets around them
![]()
there's also ⟁ for warnings, which is not semantically a warning, but it's more legible because it's bigger
![]()
Looks great!
I see you made the header text white rather than colored, including the file name. It might indeed be easier to read this way. And you replaced dashes with horizontal lines. I'm fine with these changes but I think the horizontal white lines might stand out a bit too much, wdyt?
the color wasn't intentional, just didn't bother :smile:
I like the horizontal solid lines tho
I think I like the solid lines too!
Sounds good. However, I think ⟁ is problematic in two ways:
Voting time! For errors:
![]()
/poll
Option 1:
Option 2
Option 3
Option 4
For warnings:
![]()
/poll Which option do you prefer?
Option 1: Δ
Option 2: △
Option 3: ⚠
Option 4: !
And lastly, for the final summary:
![]()
/poll Which option do you prefer?
Option 1: ∴
Option 2: Σ
Option 3: ≡
Option 4: »
I updated the PR with my preferences (I'll update if the poll results are different). Here's what the full output looks like now:
![]()
I kinda like for the summary just not having an icon or "found" - so just like "0 errors and 2 warnings" with the line and the filename
I intentionally chose the wording of that so that the very first part of the message is the thing you care about most: the number of errors
so I'd like to avoid having things before that...I think the line is fine though
Done, I updated the PR.
![]()
Do you prefer an extra empty line at the end of each section?
![]()
i like without the extra line!
I replaced ⚠ with ! and updated the PR. I quite like the format now:
![]()
If you're onboard with this change, could someone kindly review the PR (and hopefully merge it) when you have a minute? :folded_hands:
I'm not a fan of any of the warning icon options :thinking:
which is a shame
Any suggestions?
A few more options:
![]()
to my surprise, I kinda dig the solid circle
Yeah, I was thinking the same! I'll update the PR.
I'm trying to guess why it works for me; I think maybe it's that:
! could easily be misinterpreted to mean "error!" - so even if you read it and just think it's a bullet point, that's not much of a downside; in some ways it is a bullet point, so it's not misleading you, it's just uninformative. In other words, the failure mode as an icon is very mild - especially compared to the frontrunner alternatives.thanks for going through all those options @Aurélien Geron! :smiley:
I just pushed the updated PR.
Did we ever need Info severity reports?
I wonder why I added that in the original reporting module... I must have got the idea from somewhere
Ah good point, we don't anymore. I'm removing this code.
I'm seeing file paths like this, it doesnt quite look right
(tuple_bool.md:1:38):
(tuple_bool.md:1:45):
I believe that's for the secondary locations, such as in duplicate definition warnings:
![]()
How do we calculate the number of dashes to add in the header line? This is what the snapshots look like now.
![]()
I remember we had the indentation which I think the markdown files we recognised as code blocks. I'm not saying we should change our error format to suite the snapshot file markdown format, just noticed.
Regarding the secondary locations, perhaps you might prefer it without "here" and without parentheses?
![]()
Regarding the snapshots, I guess we should put the whole thing in a code block so it is rendered in the browser using a monospaced font.
Regarding the weird width, I wonder whether that's because the horizontal width character is wider than other characters when you're not using a fixed-width font?
Oh that's what you just said :sweat_smile:
This is the terminal formatting right, I guess we haven't looked at the markdown, html or other renderers from our reporting module?
Ah no, I didn't realize they had their own renderers. :face_with_open_eyes_and_hand_over_mouth:
LSP too, I forgot that. I'm not sure they need to all be in scope for this PR.
Honestly thinking about this more we should probably have the snapshots render a canonicalized debug format for the errors, possibly even an S-expression.
And then have a separate snapshot format just for errors where we render all of the variations (CLI, HTML, LSP, Markdown)
The errors in the vast majority of the snapshots would be a semantic level that doesn't change with presentation formats then.
Yes, that would be great.
Ok, probably in another PR, then? I'll update the PR to replace here (foo.roc:1:2): with in foo.roc:1.2:.
When we make changes to the reporting render formats that would be isolated to the error specific snapshot types
Yeah this is probably getting too broad to stack into this one.
I'll make an issue for the snapshot ideas
https://github.com/roc-lang/roc/issues/10720
Ok, I've asked an agent (Sol 5.6) to review the PR and fix a few issues I had noticed, in particular the way the secondary locations were handled. I read through the changes, and I think it looks good now. Btw, I tweaked one thing which I think makes the output even nicer: the ^^^^ for warnings are yellow now. So it looks like this:
![]()
Last updated: Aug 12 2026 at 12:35 UTC