hashicorp/nomad · warning

can't seek to offset %d: %w

Error message

can't seek to offset %d: %w

What it means

AllocDir.ReadAt fails when os.Seek to the requested offset on the opened alloc-dir file returns an error (e.g. offset beyond file size or an I/O error); the underlying seek error is wrapped and returned to the caller of the file-read endpoint.

Source

Thrown at client/allocdir/alloc_dir.go:510

	if strings.HasSuffix(path, ".json") {
		contentType = "application/json"
	}
	return contentType
}

// ReadAt returns a reader for a file at the path relative to the alloc dir
func (a *AllocDir) ReadAt(path string, offset int64) (io.ReadCloser, error) {
	sanitizedPath, err := a.sanitizePath(path)
	if err != nil {
		return nil, err
	}

	f, err := os.Open(sanitizedPath)
	if err != nil {
		return nil, err
	}
	if _, err := f.Seek(offset, 0); err != nil {
		return nil, fmt.Errorf("can't seek to offset %d: %w", offset, err)
	}
	return f, nil
}

// BlockUntilExists blocks until the passed file relative the allocation
// directory exists. The block can be cancelled with the passed context.
func (a *AllocDir) BlockUntilExists(ctx context.Context, path string) (chan error, error) {
	sanitizedPath, err := a.sanitizePath(path)
	if err != nil {
		return nil, err
	}

	// Get the path relative to the alloc directory
	watcher := getFileWatcher(sanitizedPath)
	returnCh := make(chan error, 1)
	t := &tomb.Tomb{}
	go func() {
		<-ctx.Done()

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Check the offset is >= 0 and the target is a regular file before calling ReadAt
  2. Handle the wrapped seek error by re-statting the file and restarting at offset 0
  3. Avoid pointing the file API at non-seekable files (pipes, sockets, devices)
  4. Refresh stale offsets after the file has been rotated or truncated

Example fix

// before
f, err := allocDir.ReadAt("task/app/log", staleOffset)
// after
fi, _ := os.Stat("task/app/log")
off := staleOffset
if !fi.Mode().IsRegular() || off > fi.Size() {
    off = 0
}
f, err := allocDir.ReadAt("task/app/log", off)
Defensive patterns

Strategy: validation

Validate before calling

fi, err := os.Stat(path)
if err != nil || !fi.Mode().IsRegular() {
    return fmt.Errorf("not a seekable regular file")
}
if offset < 0 || offset > fi.Size() {
    offset = 0
}

Try / catch

f, err := allocDir.ReadAt(relPath, off)
if err != nil && strings.Contains(err.Error(), "can't seek to offset") {
    f, err = allocDir.ReadAt(relPath, 0) // restart from beginning
}

Prevention

When it happens

Trigger: Calling ReadAt with a negative offset, or an offset beyond what the filesystem/file supports (e.g. past the end on a special file such as a pipe, device, or FIFO that is not seekable).

Common situations: Log/EOF-following logic computing an offset from a previous snapshot of a file replaced by a special file; offset from stale state after file truncation on filesystems that reject out-of-range seeks; reading non-regular files (sockets/pipes) created inside the alloc dir.

Related errors


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/d1b8830218fc0699. Report an issue: GitHub.