Found against:* gren 0.6.6, gren-lang/core 7.4.2, gren-lang/node 6.1.3, node 22
Reproduction: in https://github.com/gilramir/gren-bug-reports in 2026-09-11-writefromoffset; ./run.sh prints the figure below.
Reproduction
Write ten As, open the file for writing, put two Zs at offset 5, read it
back:
FileSystem.writeFile fsPermission (Bytes.fromString "AAAAAAAAAA") path
|> Task.andThen
(\_ -> FileHandle.openForWrite fsPermission FileHandle.ExpectExisting path)
|> Task.andThen
(\fh ->
FileHandle.writeFromOffset fh 5 (Bytes.fromString "ZZ")
|> Task.andThen (\_ -> FileHandle.close fh)
)
|> Task.andThen (\_ -> FileSystem.readFile fsPermission path)
wrote "ZZ" at offset 5 into "AAAAAAAAAA"
expected AAAAAZZAAA
got ZZAAAAAAAA
The "ZZ"'s were written at offset 0.
Reason
writeFromOffset takes the offset as a plain Int:
{-| Write bytes into a specific location of a file.
-}
writeFromOffset : WriteableFileHandle a -> Int -> Bytes -> Task FileSystem.Error (WriteableFileHandle a)
writeFromOffset =
Gren.Kernel.FileSystem.writeFromOffset
The kernel function behind it reads that argument as a record:
var _FileSystem_writeFromOffset = F3(function (fh, options, bytes) {
return __Scheduler_binding(function (callback) {
_FileSystem_writeHelper(
fh,
bytes,
0,
bytes.byteLength,
options.__$offset,
callback,
);
});
});
options is a number, so options.__$offset is undefined. That is handed to
fs.write as its position, where undefined means "wherever the file
currently is" — which for a freshly opened handle is 0.
So the offset argument has no effect at all. Every writeFromOffset writes
where write would have written.
readFromOffset beside it does take a record, { offset, length }, and is
correct. The kernel function for the write looks like a copy of the read's that
kept the record access after the Gren signature stopped passing one.
Found against:*
gren0.6.6,gren-lang/core7.4.2,gren-lang/node6.1.3, node 22Reproduction: in https://github.com/gilramir/gren-bug-reports in
2026-09-11-writefromoffset;./run.shprints the figure below.Reproduction
Write ten
As, open the file for writing, put twoZs at offset 5, read itback:
The "ZZ"'s were written at offset 0.
Reason
writeFromOffsettakes the offset as a plainInt:The kernel function behind it reads that argument as a record:
optionsis a number, sooptions.__$offsetisundefined. That is handed tofs.writeas itsposition, whereundefinedmeans "wherever the filecurrently is" — which for a freshly opened handle is 0.
So the offset argument has no effect at all. Every
writeFromOffsetwriteswhere
writewould have written.readFromOffsetbeside it does take a record,{ offset, length }, and iscorrect. The kernel function for the write looks like a copy of the read's that
kept the record access after the Gren signature stopped passing one.