gren-lang / gren-lang/node

`FileSystem.FileHandle.writeFromOffset` ignores its offset and writes at position 0

Open Beginner friendly
#63 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
JavaScript
Stars
13
Forks
6
Avg merge
5d 20h
Merged PRs (30d)
3

Description

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.

Contributor guide

No contributing guide indexed for this repository

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

Start at the Gren.Kernel.FileSystem.writeFromOffset entry point and compare its argument handling with the adjacent readFromOffset implementation. Run the reproduction's ./run.sh first; done means writing two bytes at offset 5 produces AAAAAZZAAA rather than ZZAAAAAAAA.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript
Domain
operating-systems
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
82/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.