Stream: bugs

Topic: Program has different behavior depending on `dbg` place...


view this post on Zulip Ian McLerran (Dec 25 2025 at 20:09):

Hey all - I've got a real puzzler on my hands. I have been trying to port some old AoC code to the new compiler. However, while the program passes roc build, it crashes before reaching the end of main. However, depending where, and how many dbg statements I place, the crash will occur at different places.

Also, I get some strange behavior where placing two dbg statements for the same Try value will show as the wrapped value once, and an Ok(...) the next time.

There is a third issue, which seems unrelated to the dbg issue, in which I can pipe the results of the part1() calculation to Stdout.line!(), but if I save the result of part1() as a value and then call Stdout.line!() on the value in the next line, the program crashes before reaching the Stdout.line!().

Finally, the program never finishes executing completely. It will always crash before completing, but depending on how I structure the rest of the code, I may be able to get it to print the result of part1().

view this post on Zulip Ian McLerran (Dec 25 2025 at 20:10):

I have been trying to minimize this issue, but haven't been able to due so yet.

(current code coming below)

view this post on Zulip Ian McLerran (Dec 25 2025 at 20:14):

I will give the full code below, but let me start by giving this snippet. Depending on which of these debug statements are uncommented, the program will crash in different modes, and may or may not make it back to main to execute the Stdout.line!() statement in main.

## Solve part 1
part1 : Str -> Try(Str, _)
part1 = |s| {
    s.split_on("\n")
    .map(extract_digits)
    ->keep_oks(compute_calibration)
    # ->debug() # (1)
    ->sum()
    # ->debug() # (2)
    .to_str()
    # ->debug() # (3)
    ->Ok
    # ->debug() # (4)
}

view this post on Zulip Ian McLerran (Dec 25 2025 at 20:53):

Failure Modes

Roc crashed: Internal error: TypeMismatch in call_invoke_closure continuation
thread 43720 panic: reached unreachable code
Unable to dump stack trace: debug info stripped
Aborted (core dumped)
dbg: []
209.0

Roc crashed: call_invoke_closure: value_stack empty when popping function
dbg: []
209.0

Roc crashed: non-exhaustive match
dbg: []
dbg: "209.0"
209.0

Roc crashed: non-exhaustive match
dbg: []
dbg: []
dbg: "209.0"
209.0

Roc crashed: non-exhaustive match

view this post on Zulip Ian McLerran (Dec 25 2025 at 20:54):

Note that debug is defined as:

debug : a -> a
debug = |v| {
    dbg v
    v
}

view this post on Zulip Ian McLerran (Dec 25 2025 at 20:58):

I'll come back and document some of the other issues later, but for now, here is the full code file:

app [main!] { pf: platform "https://github.com/lukewilliamboswell/roc-platform-template-zig/releases/download/0.6/2BfGn4M9uWJNhDVeMghGeXNVDFijMfPsmmVeo6M4QjKX.tar.zst" }

import pf.Stdout

main! = |_args| {
    input =
        \\two1nine
        \\eightwothree
        \\abcone2threexyz
        \\xtwone3four
        \\4nineeightseven2
        \\zoneight234
        \\7pqrstsixteen

    part1(input)?->Stdout.line!()

    # answer1 = part1(input)?->debug()->debug()->debug()
    # dbg "answer"
    # Stdout.line!(answer1)

    Ok({})
}

## Solve part 1
part1 : Str -> Try(Str, _)
part1 = |s| {
    s.split_on("\n")
    .map(extract_digits)
    ->keep_oks(compute_calibration)
    ->debug() # (1)
    ->sum()
    # ->debug() # (2)
    .to_str()
    # ->debug() # (3)
    ->Ok
    ->debug() # (4)
}

extract_digits : Str -> List(U64)
extract_digits = |s| {
    s.to_utf8()
        .keep_if(|c| c >= '0' and c <= '9')
        .map(|c| (c - '0').to_u64())
}

compute_calibration : List(U64) -> Try(U64, _)
compute_calibration = |digits| Ok(List.first(digits)? * 10 + List.last(digits)?)

## Solve part 2
part2 : Str -> Try(Str, _)
part2 = |s| {
    s.split_on("\n")
        .map(extract_text_digits)
        ->keep_oks(compute_calibration)
        ->debug()
        ->sum()
        .to_str()
        ->Ok
}

extract_text_digits : Str -> List(U64)
extract_text_digits = |s| {
    bytes = s.to_utf8()
    (0).to(bytes.len())
        .fold(
            [],
            |ds, i| {
                match bytes.drop_first(i) {
                    ['o', 'n', 'e', ..] => ds.append(1)
                    ['t', 'w', 'o', ..] => ds.append(2)
                    ['t', 'h', 'r', 'e', 'e', ..] => ds.append(3)
                    ['f', 'o', 'u', 'r', ..] => ds.append(4)
                    ['f', 'i', 'v', 'e', ..] => ds.append(5)
                    ['s', 'i', 'x', ..] => ds.append(6)
                    ['s', 'e', 'v', 'e', 'n', ..] => ds.append(7)
                    ['e', 'i', 'g', 'h', 't', ..] => ds.append(8)
                    ['n', 'i', 'n', 'e', ..] => ds.append(9)
                    ['z', 'e', 'r', 'o', ..] => ds.append(0)
                    [d, ..] => if d >= '0' and d <= '9' ds.append((d - '0').to_u64()) else ds
                    [] => ds
                }
            },
        )
}

keep_oks : List(a), (a -> Try(b, e)) -> List(b)
keep_oks = |vs, f| {
    vs.fold(
        [],
        |acc, v| {
            match f(v) {
                Ok(u) => acc.append(u)
                Err(_) => acc
            }
        },
    )
}

sum : List(Num) -> Num
sum = |nums| nums.fold(0, |acc, n| acc + n)

debug : a -> a
debug = |v| {
    dbg v
    v
}

view this post on Zulip Richard Feldman (Dec 25 2025 at 22:08):

I'll look into this!

view this post on Zulip Richard Feldman (Dec 26 2025 at 00:26):

@Ian McLerran I have a fix in https://github.com/roc-lang/roc/pull/8752/changes - just cleaning it up now

view this post on Zulip Richard Feldman (Dec 26 2025 at 00:27):

tl;dr stack corruption in the interpreter - dbg was not really related, it just triggered the bug because involved the stack :smile:

view this post on Zulip Ian McLerran (Dec 26 2025 at 01:16):

Ahh, that makes sense! Changing the debug calls just changed the stack, hence the different results.

view this post on Zulip Notification Bot (Dec 26 2025 at 01:40):

Ian McLerran has marked this topic as resolved.

view this post on Zulip Notification Bot (Dec 26 2025 at 02:56):

Ian McLerran has marked this topic as unresolved.

view this post on Zulip Ian McLerran (Dec 26 2025 at 03:18):

Thanks for tackling this @Richard Feldman! I built off the latest main, and I can see that most of the failure modes are fixed! (I can remove all the debugs, and the program compiles, regardless of whether I print from the pipe, or save the value and print)

Looks like this code also raises a couple other bugs if I reintroduce some debug() calls:
1) If I reintroduce (1) and (2):

- debug (2) prints an empty list, where it should print the integer value "209"
2) If I reintroduce (2), (3), or (4) only:

- crashes with: Roc crashed: Internal error: TypeMismatch in call_invoke_closure continuation

view this post on Zulip Richard Feldman (Dec 26 2025 at 03:19):

ah interesting! I'll follow up!

view this post on Zulip Ian McLerran (Jan 14 2026 at 16:45):

Seems like the behavior of this code has changed since 20 days ago. Now when I build, regardless of dbg statements included (or not included), the program will build, but then crashes at run time with:

Roc crashed: Error evaluating: NotNumeric

view this post on Zulip Anton (Jan 14 2026 at 17:00):

I will minimize this and make an issue

view this post on Zulip Anton (Jan 14 2026 at 17:28):

#9020 I have described a workaround there as well

view this post on Zulip Ian McLerran (Jan 14 2026 at 17:29):

Thanks Anton!

view this post on Zulip Ian McLerran (Jan 14 2026 at 17:44):

@Anton Great work chopping that thing down! I was trying to do the same but did not get nearly this far! :sweat_smile:

view this post on Zulip Ian McLerran (Jan 14 2026 at 17:45):

Just looking at your reproduction and work around... I see your repro was using a local closure, and the work around is to move the local closure to a top level closure.

It looks like the local closure f in your code corresponds to compute_calibration in my code, but in my code, compute_calibration is top level, not local... Seems like there might be something else going on here?

view this post on Zulip Anton (Jan 14 2026 at 18:35):

Yeah, it seems like a complex interaction, I have included your original code as well to make sure it works when the issue appears to be fixed.


Last updated: Feb 20 2026 at 12:27 UTC