Hello all,
Here's a pretty simple app which is walking down directories starting with a root path provided as a command line argument. I call it like so :
roc --no-cache -- /Users
I'm using the latest basic-cli platform available and the corresponding nightly version or Roc, but I get the same result with the most recent Roc build.
The issue is that it never recurses deeper than 7 levels and sometimes gives me the following crash :
*Roc crashed: RocList.refcount: getAllocationDataPtr returned null (capacity=4416949544, is_slice=false)*
The crash doesn't seem random as if I get it for a specific root directory, I'll get it consistently. But not every root path results in a crash.
app [main!] { pf: platform "https://github.com/roc-lang/basic-cli/releases/download/alpha-0/HVZonS7HStbvGwhqvDZE1HreyDfqD6tayzFbi9rAUXYN.tar.zst"}
import pf.Stdout
import pf.Dir
import pf.Path
main! = |args| {
root_path = args.get(1)?
files = walk_directory!(root_path, Bool.False)
Stdout.line!(Str.inspect(files))
Ok({})
}
walk_directory! : Str, Bool => List(Str)
walk_directory! = |root_path, include_invisibles| {
dbg(root_path)
content = dir_content!(root_path, include_invisibles)
fold!(content.dirs, [], |dirs, d| {dirs.concat(walk_directory!(d, include_invisibles))})
}
dir_content! : Str, Bool => {dirs: List(Str), files: List(Str)}
dir_content! = |root_path, include_invisibles| {
content = match Dir.list!(root_path) {
Ok(c) => c
Err(e) => {
dbg(e)
[]
}
}
fold!(content, {files: [], dirs: []},
|state, path| {
if include_invisibles.not() and path_is_visible(path).not() {
state
} else if Path.is_file!(path).ok_or(Bool.False) {
{..state, files: state.files.append(path)}
} else if Path.is_dir!(path).ok_or(Bool.False) {
{..state, dirs: state.dirs.append(path)}
} else {
state
}
}
)
}
fold! : List(item), state, (state, item => state) => state
fold! = |list, init, step| {
var $state = init
for item in list {
$state = step($state, item)
}
$state
}
path_is_visible : Str -> Bool
path_is_visible = |path| {
basename(path).starts_with(".").not()
}
basename : Str -> Str
basename = |path| {
path.split_on("/").last().ok_or("")
}
Before asking my questions I tried my best to exhaust all other possibilities except using AI. Is there a mini guide somewhere in the discussions on how I could set one up, maybe in combination with Zed?
Thank you so much for the help and, mostly, for all the hard work on this amazing language!
Hi @Claude Précourt, I am done for today but I can take a look tomorrow and provide you with an AI prompt as well :)
So kind of you @Anton ! There is obviously no rush, no code in production here.
Here is the workaround, using more for loops instead of fold:
app [main!] { pf: platform "../platform/main.roc" }
import pf.Stdout
import pf.Dir
import pf.Path
main! = |args| {
root_path = args.get(1)?
files = walk_directory!(root_path, Bool.False)
Stdout.line!(Str.inspect(files))
Ok({})
}
walk_directory! : Str, Bool => List(Str)
walk_directory! = |root_path, include_invisibles| {
dbg(root_path)
dirs = get_subdirs!(root_path, include_invisibles)
var $result = dirs
$result = []
for d in dirs {
$result = $result.concat(walk_directory!(d, include_invisibles))
}
$result
}
get_subdirs! : Str, Bool => List(Str)
get_subdirs! = |root_path, include_invisibles| {
content = match Dir.list!(root_path) {
Ok(c) => c
Err(e) => {
dbg(e)
[]
}
}
var $dirs = content
$dirs = []
for path in content {
if include_invisibles.not() and path_is_visible(path).not() {
{}
} else if Path.is_dir!(path).ok_or(Bool.False) {
$dirs = $dirs.append(path)
}
}
$dirs
}
path_is_visible : Str -> Bool
path_is_visible = |path| {
basename(path).starts_with(".").not()
}
basename : Str -> Str
basename = |path| {
path.split_on("/").last().ok_or("")
}
This was my prompt for Opus 4.6 (Effort High) in Claude Code:
"""
Looks like I am hitting a segmentation fault, please investigate:
❯ ./roc_nightly-macos_apple_silicon-2026-02-24-9d46896/roc --no-cache ./examples/dir-walk-crash.roc /Users/username/gitrepos/basic-cli4/basic-cli
dbg: "/Users/username/gitrepos/basic-cli4/basic-cli"
dbg: "/Users/username/gitrepos/basic-cli4/basic-cli/crates"
dbg: "/Users/username/gitrepos/basic-cli4/basic-cli/crates/roc_host_lib"
dbg: "/Users/username/gitrepos/basic-cli4/basic-cli/crates/roc_host_lib/src"
❯ echo $?
139
You are working in basic-cli, a Roc platform made with Roc and Rust. Passing things between Roc and Rust requires special care and is prone to issue with the memory.
The source code of zig 0.15.2 is in /Users/username/gitrepos/zig, you can use it as documentation.
If you make any changes inside basic-cli that are not in the examples folder, you will most likely need to rebuild with ./build.sh
After you are done, run ./ci/all_tests.sh to confirm you did not break anything else.
You can find the source code for the nightly release at /Users/username/gitrepos/roc. That repo contains the Roc CLI, a compiler and interpreter written in zig. Ignore everything in the crates folder there, exclude it from all your searches.
You can rebuild the roc binary with zig build roc, this will put it in ./zig-out/bin/roc.
Debugging:
zig build roc -Dtrace-refcountStyle:
If you encounter a network error when fetching dependencies, just run the command again.
Some zig commands do not output anything on success and just exit with code 0.
Note that zig test often does not work with our project, so we typically rely on zig build test, the flag --summary all can give your more info about which tests ran. You can run a single test with zig build test -- --test-filter "substring that occurs in test name". If you add --summary all it must be located before the -- --test-filter.
It's recommended to always run with --no-cache, so ./zig-out/bin/roc myfile.roc --no-cache, to prevent caching from behaving in unexpected ways.
Note that Roc has changed since your training data, it's recommended to check existing .roc files in the repo if you're getting confusing errors when adding Roc code.
"""
Here are instructions for the initial setup:
"""
The debugging process:
git clone https://github.com/roc-lang/basic-cli.git
cd basic-cli
git checkout migrate-zig-compiler
Get commit from latest nightly at https://github.com/roc-lang/nightlies/releases: 9d46896bdfbb44f915a935d77b69ea86cdc23e78
In your local basic-cli folder, update the rev for roc_std_new in Cargo.toml to 9d46896bdfbb44f915a935d77b69ea86cdc23e78
run ./ci/all_tests.sh as a sanity check. You will need to have zig 0.15.2 installed.
Create ./examples/dir-walk-crash.roc, changing the header to: app [main!] { pf: platform "../platform/main.roc" }
I ran the following:
❯ ./roc_nightly-macos_apple_silicon-2026-02-24-9d46896/roc --no-cache ./examples/dir-walk-crash.roc /Users/username/gitrepos/basic-cli4/basic-cli
dbg: "/Users/username/gitrepos/basic-cli4/basic-cli"
dbg: "/Users/username/gitrepos/basic-cli4/basic-cli/crates"
dbg: "/Users/username/gitrepos/basic-cli4/basic-cli/crates/roc_host_lib"
dbg: "/Users/username/gitrepos/basic-cli4/basic-cli/crates/roc_host_lib/src"
❯ echo $?
139
Exit code 139 means a segmentation fault.
I set my local Roc repo to the same commit as the nightly git checkout 9d46896bdfbb44f915a935d77b69ea86cdc23e78.
"""
Claude thinks the bug is in Roc itself, not basic-cli, so I will look into a fix there too.
So the workaround is to use a less of a functional approach for now. I, Claude Human tend agree with Claude AI that the bug is in Roc itself. While debugging I added many dbg() statements everywhere I was calling effectful methods of basic-cli to make sure that I wasn't silently failing somewhere when interacting with the file system.
And thanks @Anton for the example prompt. I need to invest more time to get better at this AI stuff... ;-)
I, Claude Human
everybody is talking about you these days :smile:
I know! It was funny at first. Especially since I've always been the go to guy for all sorts of weird requests everywhere I have worked at. But now I must admit that it's just weird and mildly annoying seeing my first name used so often... At least Anthropic seems to have a good reputation and seems more ethical than most!
Anton aus Tirol used to be a hit song when I was a child, but yeah this is something else :p
It would be nice if you were able to use it to get a pay raise if some out of touch higher up manager has been hearing office chatter about how Claude is making them so much more productive :smile:
Great idea! I'll ask Claude to compose an email for me...!
I just listened to "Anton aus Tirol" and... it helped me make peace with having an AI homonym. :wink:
Anton said:
Claude thinks the bug is in Roc itself, not basic-cli, so I will look into a fix there too.
Fixed in #9200
Yeah I was going to guess it's most likely in the interpreter :sweat_smile:
Last updated: Mar 20 2026 at 12:28 UTC