denoland/deno · error

An attempt was made to move the file pointer before the begi

Error message

An attempt was made to move the file pointer before the beginning of the file.

What it means

Raised by `FileBackedVfsFile::seek` when a `SeekFrom::End(offset)` call would place the read pointer before byte 0: the negative offset's magnitude exceeds the file's length. The VFS rejects it with `io::ErrorKind::PermissionDenied` (the classic Windows `ERROR_NEGATIVE_SEEK` message) instead of letting the position underflow.

Source

Thrown at cli/rt/file_system.rs:1334

}

pub struct FileBackedVfsFile {
  file: VirtualFile,
  pos: RefCell<u64>,
  vfs: Arc<FileBackedVfs>,
}

impl FileBackedVfsFile {
  pub fn seek(&self, pos: SeekFrom) -> std::io::Result<u64> {
    match pos {
      SeekFrom::Start(pos) => {
        *self.pos.borrow_mut() = pos;
        Ok(pos)
      }
      SeekFrom::End(offset) => {
        if offset < 0 && -offset as u64 > self.file.offset.len {
          let msg = "An attempt was made to move the file pointer before the beginning of the file.";
          Err(std::io::Error::new(
            std::io::ErrorKind::PermissionDenied,
            msg,
          ))
        } else {
          let mut current_pos = self.pos.borrow_mut();
          *current_pos = if offset >= 0 {
            self.file.offset.len - (offset as u64)
          } else {
            self.file.offset.len + (-offset as u64)
          };
          Ok(*current_pos)
        }
      }
      SeekFrom::Current(offset) => {
        let mut current_pos = self.pos.borrow_mut();
        if offset >= 0 {
          *current_pos += offset as u64;
        } else if -offset as u64 > *current_pos {

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Clamp the offset to the file length: seek to `-Math.min(n, len)` after reading `len` from `file.stat()`.
  2. Use `SeekFrom::Start` / `Deno.SeekMode.Start` when the absolute target position is known.
  3. Validate input file size before running seek-based parsing and reject truncated files early.

Example fix

// before
await file.seek(-4096, Deno.SeekMode.End); // throws if file < 4096 bytes

// after
const { size } = await file.stat();
await file.seek(-Math.min(4096, size), Deno.SeekMode.End);
Defensive patterns

Strategy: validation

Validate before calling

// before any negative End seek
const { size } = await file.stat();
const safe = Math.min(requestedBackstep, size);
await file.seek(-safe, Deno.SeekMode.End);

Try / catch

try {
  await file.seek(-n, Deno.SeekMode.End);
} catch (err) {
  if (err instanceof Deno.errors.PermissionDenied) { /* clamp and retry once */ }
  else throw err;
}

Prevention

When it happens

Trigger: Calling `file.seek(SeekFrom::End(-n))` (Rust) or `file.seek(-n, Deno.SeekMode.End)` (JS) where n is greater than the file's byte length, on a file opened from the embedded VFS of a compiled binary. Any negative offset on an empty file also triggers it.

Common situations: Rewinding a fixed block size (e.g. seek -4096 to re-read a footer) on files smaller than that block; ported parsers that assume seek-before-start clamps to 0; truncated input files.

Related errors


AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20). Data as JSON: /api/errors/78e72522c1e9e86d. Report an issue: GitHub.