Stream: contributing

Topic: Richer Path errors (basic-cli #399)


view this post on Zulip Dzmitry Misiuk (Aug 02 2026 at 17:21):

I'd like to take #399 (cc @Anton as the author). Today every Path effect returns PathErr(IOErr), so a failure prints as PathErr(NotFound) with no indication of which path — or which of several calls — failed. The path is already in hand at the failure point, so this is pure Roc in Path.roc; no host or glue changes.

Two things I'd like to agree before writing it.

1. Positional or record payload? The platform has both:

PathErr(IOErr, Path)                     # like Sqlite's SqliteErr(ErrCode, Str)
PathErr({ path : Path, err : IOErr })    # like Cmd's FailedToGetExitCode({ command, err })

I lean positional, for one concrete reason: Err(PathErr(NotFound, _)) still works, so the common one-liner survives — including in the platform's own is_file! / is_dir! / exists!. With a record those become full destructures (I couldn't find any { field, .. } partial patterns in the repo).

2. Include the operation as well? The triage note mentions "operation/path context", but I lean toward path-only: it costs every signature, and it only adds information when two different operations hit the same path. Happy to include it if you'd rather have it.

Either way this is a breaking change, though a narrow one — ?, ? |err| …, ?? and Err(_) all keep working, since the error type is open and inferred. Only an explicit destructure of the inner tag breaks: 6 spots in the platform and 6 lines across two examples, which I'd update in the same PR.

(Sqlite.prepare! deliberately keeps path/query out of SqliteErr, so "leave it as-is" is a legitimate answer too — I'd rather hear that now than after the PR.)

view this post on Zulip Dzmitry Misiuk (Aug 02 2026 at 18:41):

Put it up as #468, implementing the positional option — easier to judge the shape against real code, and switching to a record is a mechanical pass either way.

One question while you're there: File.open_reader! takes a Path but returns a bare FileErr, so whether an open error names the path would depend on which module you called. Fold it in, or follow-up?

view this post on Zulip Anton (Aug 03 2026 at 13:58):

  1. Positional or record payload?

Positional looks good

Include the operation as well?

Let's try without for now, we can always change it later.

File.open_reader! takes a Path but returns a bare FileErr, so whether an open error names the path would depend on which module you called. Fold it in, or follow-up?

Let's add the path there too in the same PR.

view this post on Zulip Dzmitry Misiuk (Aug 03 2026 at 18:40):

Done in #468 — one wrinkle on the File one: FileErr(err, path) doesn't work, since read_line! keeps returning FileErr(IOErr) (a Reader has no path) and one tag name can't have two arities. So open_reader! reports PathErr(err, path) instead, which also means an open and a Path op unify in one ? chain. Shout if you'd rather keep the FileErr name and change Reader instead.


Last updated: Aug 12 2026 at 12:35 UTC