wavetermdev/waveterm · error

offset must be non-negative

Error message

offset must be non-negative

What it means

FileStore.WriteAt rejects any negative offset before touching the file. Writes to a block-backed file must start at a non-negative byte offset since the offset is mapped onto fixed-size data parts in the DB. The check happens up front so no lock or cache load occurs for an obviously invalid call.

Source

Thrown at pkg/filestore/blockstore.go:242

		return nil
	})
}

func (s *FileStore) WriteFile(ctx context.Context, zoneId string, name string, data []byte) error {
	return withLock(s, zoneId, name, func(entry *CacheEntry) error {
		err := entry.loadFileIntoCache(ctx)
		if err != nil {
			return err
		}
		entry.writeAt(0, data, true)
		// since WriteFile can *truncate* the file, we need to flush the file to the DB immediately
		return entry.flushToDB(ctx, true)
	})
}

func (s *FileStore) WriteAt(ctx context.Context, zoneId string, name string, offset int64, data []byte) error {
	if offset < 0 {
		return fmt.Errorf("offset must be non-negative")
	}
	return withLock(s, zoneId, name, func(entry *CacheEntry) error {
		err := entry.loadFileIntoCache(ctx)
		if err != nil {
			return err
		}
		file := entry.File
		if offset > file.Size {
			return fmt.Errorf("offset is past the end of the file")
		}
		partMap := file.computePartMap(offset, int64(len(data)))
		incompleteParts := incompletePartsFromMap(partMap)
		err = entry.loadDataPartsIntoCache(ctx, incompleteParts)
		if err != nil {
			return err
		}
		entry.writeAt(offset, data, false)
		return nil

View on GitHub (pinned to a4447c1563)

Solutions

  1. Validate offset >= 0 in the caller before invoking WriteAt.
  2. Fix the offset arithmetic that produced the negative value (check subtraction order and underflow).
  3. If appending is intended, compute offset from the current file size via a stat/ReadAt of size 0 instead of a sentinel.

Example fix

// before
fs.WriteAt(ctx, zone, name, -1, data) // meant 'append'
// after
var offset int64 = 0 // or track the known file size
if offset < 0 { return fmt.Errorf("invalid offset %d", offset) }
fs.WriteAt(ctx, zone, name, offset, data)
Defensive patterns

Strategy: validation

Validate before calling

if offset < 0 { return fmt.Errorf("WriteAt: offset %d must be >= 0", offset) }

Type guard

func validOffset(offset int64) bool { return offset >= 0 }

Prevention

When it happens

Trigger: Calling WriteAt(ctx, zoneId, name, offset, data) with offset < 0, typically because an offset was computed from a subtraction (e.g. size - remaining) that underflowed, or a caller passed -1 as an 'unset' sentinel.

Common situations: Arithmetic on int64 offsets overflowing/underflowing, sentinel values like -1 used for 'append' mistakenly, or deserializing offsets from JSON/binary where a missing field defaults to a negative value.

Related errors


AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01). Data as JSON: /api/errors/9560f6ae28d00e14. Report an issue: GitHub.