Dzmitry Misiuk has marked this topic as unresolved.
Following up: the bare encoder_for : _ / parser_for : _ derives fine for an opaque over a record, but not for one over a primitive — the validated-newtype case, e.g. a Username := Str carrying a min-length that should drive its codec and its schema from one declaration:
Username := Str.{ encoder_for : _ }
expect Json.to_str(Username.("ada")) == "\"ada\"" # nightly: {} main: panics (encoder_for selected an unsupported shape)
The derived parser panics the same way.
The cause is small: shapeContent peels the nominal to its backing, a record backing hits a shape the encoder/parser already handle, but a primitive backing hits a scalar they don't. I have a fix — peel one layer, encode/parse the backing, wrap/unwrap the value across the .nominal boundary (mirrors the record path; ~85 lines, minici green, JsonEncodeRoundTrip still passes).
One call for you: peel or reject? I did peel — support it, consistent with records, and it's format-generic (a derived encoder_for : _ on a non-JSON custom format works too, so it helps any Encoding codec, not just JSON). If you'd rather reject-for-now, I'll flip it. Happy to open a draft PR whenever you want the diff.
that's a bug, can you open a GitHub issue for it?
I can implement the fix, no problem
Opened: https://github.com/roc-lang/roc/issues/10425 — repro, root cause, and the suggested fix (both halves) are in there. I've got a working patch too (minici green) if it saves you time, but all yours.
Opened a PR for #10425: https://github.com/roc-lang/roc/pull/10495 — covers the infallible scalar backings, with the fallible-float bit flagged as a follow-up. All yours to take or land.
Follow-up to #10495: the fallible-float boundary is now closed at the checker — Money := F64.{ encoder_for : _ } gets the same clean TYPE MISMATCH as a bare F64 instead of panicking. PR: https://github.com/roc-lang/roc/pull/10519
@Dzmitry Misiuk let's not do Money := F64 - Dec should always be used for money! :smile:
Ha, fair — renamed the example to Ratio := F64Latitude := F64 (Dec for money, noted :smile:). The rejection behavior is the same.
Last updated: Aug 12 2026 at 12:35 UTC