{"record":{"id":"f11b5ddfe428a3bc","repo":"wavetermdev/waveterm","slug":"size-must-be-non-negative-and-less-than-maxint","errorCode":null,"errorMessage":"size must be non-negative and less than MaxInt","messagePattern":"size must be non-negative and less than MaxInt","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/filestore/blockstore.go","lineNumber":372,"sourceCode":"\t\tif numCmds > IJsonHighCommands || incRatio >= IJsonHighRatio || (numCmds > IJsonLowCommands && incRatio >= IJsonLowRatio) {\n\t\t\terr := s.compactIJson(ctx, entry)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\treturn nil\n\t})\n}\n\nfunc (s *FileStore) GetAllZoneIds(ctx context.Context) ([]string, error) {\n\treturn dbGetAllZoneIds(ctx)\n}\n\n// returns (offset, data, error)\n// we return the offset because the offset may have been adjusted if the size was too big (for circular files)\nfunc (s *FileStore) ReadAt(ctx context.Context, zoneId string, name string, offset int64, size int64) (rtnOffset int64, rtnData []byte, rtnErr error) {\n\tif size < 0 || size > math.MaxInt {\n\t\treturn 0, nil, fmt.Errorf(\"size must be non-negative and less than MaxInt\")\n\t}\n\twithLock(s, zoneId, name, func(entry *CacheEntry) error {\n\t\trtnOffset, rtnData, rtnErr = entry.readAt(ctx, offset, size, false)\n\t\treturn nil\n\t})\n\treturn\n}\n\n// returns (offset, data, error)\nfunc (s *FileStore) ReadFile(ctx context.Context, zoneId string, name string) (rtnOffset int64, rtnData []byte, rtnErr error) {\n\twithLock(s, zoneId, name, func(entry *CacheEntry) error {\n\t\trtnOffset, rtnData, rtnErr = entry.readAt(ctx, 0, 0, true)\n\t\treturn nil\n\t})\n\treturn\n}\n\ntype FlushStats struct {","sourceCodeStart":354,"sourceCodeEnd":390,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/filestore/blockstore.go#L354-L390","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Clamp size to the actual file size before calling ReadAt (obtain it via ReadAt with a small size/stat or track it).","Pass a bounded size (e.g. remaining bytes = file.Size - offset) instead of a sentinel.","Read large files in chunks in a loop rather than one MaxInt-sized request."],"exampleFix":"// before\ndata, err := fs.ReadAt(ctx, zone, name, 0, -1) // meant 'read all'\n// after\nsize := int64(1 << 20)\nrtnOffset, data, err := fs.ReadAt(ctx, zone, name, 0, size)","handlingStrategy":"validation","validationCode":"if size < 0 || size > math.MaxInt { return fmt.Errorf(\"invalid read size %d\", size) }","typeGuard":"func validReadSize(size int64) bool { return size >= 0 && size <= math.MaxInt }","tryCatchPattern":null,"preventionTips":["Never pass -1 or math.MaxInt64 as a 'read everything' sentinel.","Compute size from the real file size (file.Size - offset) and clamp.","Read large files in bounded chunks."],"tags":["filestore","validation","arguments"],"backgroundTag":"invalid-argument-size","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}