wavetermdev/waveterm · error

offset cannot be negative

Error message

offset cannot be negative

What it means

CacheEntry.readAt rejects negative offsets before loading the file. ReadAt is the main caller, but it can also be reached via compactIJson; the internal entry-level check catches offsets that the public wrapper did not pre-validate.

Source

Thrown at pkg/filestore/blockstore_cache.go:208

			partIdx = partIdx % maxPart
		}
		partOffset := offset % partDataSize
		partData := entry.getOrCreateDataCacheEntry(partIdx)
		nw, newDce := partData.writeToPart(partOffset, data)
		entry.DataEntries[partIdx] = newDce
		data = data[nw:]
		offset += nw
	}
	if endWriteOffset > entry.File.Size || replace {
		entry.File.Size = endWriteOffset
	}
	entry.File.ModTs = time.Now().UnixMilli()
}

// returns (realOffset, data, error)
func (entry *CacheEntry) readAt(ctx context.Context, offset int64, size int64, readFull bool) (int64, []byte, error) {
	if offset < 0 {
		return 0, nil, fmt.Errorf("offset cannot be negative")
	}
	file, err := entry.loadFileForRead(ctx)
	if err != nil {
		return 0, nil, err
	}
	if readFull {
		size = file.Size - offset
	}
	if offset+size > file.Size {
		size = file.Size - offset
	}
	if file.Opts.Circular {
		realDataOffset := int64(0)
		if file.Size > file.Opts.MaxSize {
			realDataOffset = file.Size - file.Opts.MaxSize
		}
		if offset < realDataOffset {
			truncateAmt := realDataOffset - offset

View on GitHub (pinned to a4447c1563)

Solutions

  1. Validate offset >= 0 before calling ReadAt or any compaction entry point.
  2. If triggered from compactIJson, inspect the file's part map/size for corrupt metadata that yields negative offsets.
  3. Clamp computed offsets (e.g. max(0, computed)) where arithmetic can underflow.

Example fix

// before
fs.ReadAt(ctx, zone, name, userOffset, 1024) // userOffset unchecked
// after
if userOffset < 0 { return fmt.Errorf("invalid offset") }
fs.ReadAt(ctx, zone, name, userOffset, 1024)
Defensive patterns

Strategy: validation

Validate before calling

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

Type guard

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

Prevention

When it happens

Trigger: Calling ReadAt with offset < 0, or compactIJson internally computing a negative offset from file state (e.g. a part offset calculation on a corrupt/oddly-sized file).

Common situations: Sentinel -1 offsets; offset arithmetic underflow in compaction; passing user-supplied offsets straight through without validation.

Related errors


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