gren-lang / gren-lang/core

A decoder that uses `Bytes.Decode.fail` crashes instead of returning `Nothing`

Open
#152 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
JavaScript
Stars
48
Forks
14
Avg merge
4h 14m
Merged PRs (30d)
1

Description

Found against: gren 0.6.6, gren-lang/core 7.4.2, node 22
Reproduction: in https://github.com/gilramir/gren-bug-reports, 2026-09-13-bytes-decode-fail; ./run.sh prints both runs
below.

Summary

src/Main.gren is the example from Bytes.Decode.fail's own documentation: a
tag byte picks a decoder, and an unknown tag is fail.

distance : Decode.Decoder String
distance =
    Decode.unsignedInt8
        |> Decode.andThen
            (\tag ->
                when tag is
                    0 -> Decode.map (\_ -> "yards") (Decode.float32 Bytes.BE)
                    1 -> Decode.map (\_ -> "meters") (Decode.float32 Bytes.BE)
                    _ -> Decode.fail
            )

Decode.decode distance should give Nothing for an unknown tag. Instead the
program crashes.

input Decode.decode distance expected
tag 0, then a float Just "yards" Just "yards"
tag 0, then no float Nothing Nothing
tag 7, then a float throws 0 Nothing

fail is _Bytes_decodeFailure, which does throw 0. _Bytes_decode catches
only RangeError, the error a DataView read past the end raises, and rethrows
everything else:

var _Bytes_decode = F2(function (decoder, bytes) {
  try {
    return __Maybe_Just(A2(decoder, bytes, 0).__$value);
  } catch (e) {
    if (e instanceof RangeError) {
      return __Maybe_Nothing;
    } else {
      throw e;
    }
  }
});

So running out of input is Nothing, and fail escapes as an uncaught 0. The
narrowing is commit 397368a, "Only return Nothing from Bytes.decode on RangeError
exceptions", first released in core 5.0.0. It
answers core#47 (elm/bytes#9), where a stack overflow inside a decoder came back
as Nothing.

Reproduction

./run.sh builds the program and runs it twice:

$ node app
known tag:        Just yards
input too short:  Nothing
exit status: 0

$ node app direct
0
exit status: 0

With no argument, each line is decoded inside its own task. The third line never
appears, stderr is empty and the exit status is 0. With direct, the same decode
runs outside any task, and node prints the thrown 0. The exit status is still 0.
That part is compiler#385 (a crashing program exits zero) and core#142 (an
exception raised after a stream write is swallowed), not this report

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Run ./run.sh in the linked 2026-09-13-bytes-decode-fail reproduction and compare the two outputs. Then locate the _Bytes_decode entry point shown in the report and trace how Bytes.Decode.fail is handled alongside RangeError. Done means an unknown tag returns Nothing without changing the existing short-input behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript
Domain
backend
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.