wavetermdev/waveterm · error

size must be non-negative and less than MaxInt

Error message

size must be non-negative and less than MaxInt

What it means

ReadAt validates the requested size up front: it must be >= 0 and fit in an int. Sizes beyond math.MaxInt or negative sizes cannot be satisfied as a returned byte slice and would break downstream slice allocation, so the call fails immediately.

Source

Thrown at pkg/filestore/blockstore.go:372

		if numCmds > IJsonHighCommands || incRatio >= IJsonHighRatio || (numCmds > IJsonLowCommands && incRatio >= IJsonLowRatio) {
			err := s.compactIJson(ctx, entry)
			if err != nil {
				return err
			}
		}
		return nil
	})
}

func (s *FileStore) GetAllZoneIds(ctx context.Context) ([]string, error) {
	return dbGetAllZoneIds(ctx)
}

// returns (offset, data, error)
// we return the offset because the offset may have been adjusted if the size was too big (for circular files)
func (s *FileStore) ReadAt(ctx context.Context, zoneId string, name string, offset int64, size int64) (rtnOffset int64, rtnData []byte, rtnErr error) {
	if size < 0 || size > math.MaxInt {
		return 0, nil, fmt.Errorf("size must be non-negative and less than MaxInt")
	}
	withLock(s, zoneId, name, func(entry *CacheEntry) error {
		rtnOffset, rtnData, rtnErr = entry.readAt(ctx, offset, size, false)
		return nil
	})
	return
}

// returns (offset, data, error)
func (s *FileStore) ReadFile(ctx context.Context, zoneId string, name string) (rtnOffset int64, rtnData []byte, rtnErr error) {
	withLock(s, zoneId, name, func(entry *CacheEntry) error {
		rtnOffset, rtnData, rtnErr = entry.readAt(ctx, 0, 0, true)
		return nil
	})
	return
}

type FlushStats struct {

View on GitHub (pinned to a4447c1563)

Solutions

  1. Clamp size to the actual file size before calling ReadAt (obtain it via ReadAt with a small size/stat or track it).
  2. Pass a bounded size (e.g. remaining bytes = file.Size - offset) instead of a sentinel.
  3. Read large files in chunks in a loop rather than one MaxInt-sized request.

Example fix

// before
data, err := fs.ReadAt(ctx, zone, name, 0, -1) // meant 'read all'
// after
size := int64(1 << 20)
rtnOffset, data, err := fs.ReadAt(ctx, zone, name, 0, size)
Defensive patterns

Strategy: validation

Validate before calling

if size < 0 || size > math.MaxInt { return fmt.Errorf("invalid read size %d", size) }

Type guard

func validReadSize(size int64) bool { return size >= 0 && size <= math.MaxInt }

Prevention

When it happens

Trigger: Calling ReadAt(ctx, zoneId, name, offset, size) with size < 0 or size > math.MaxInt — e.g. passing -1 to mean 'read all', or computing size as an unbounded int64 sum of part sizes.

Common situations: Using -1 or math.MaxInt64 as a sentinel for 'read the whole file'; int overflow when casting buffer lengths; copying size values from APIs that use signed 64-bit sizes.

Related errors


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