{"record":{"id":"3c5edb4aeb927516","repo":"wavetermdev/waveterm","slug":"max-size-must-be-non-negative","errorCode":null,"errorMessage":"max size must be non-negative","messagePattern":"max size must be non-negative","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/filestore/blockstore.go","lineNumber":117,"sourceCode":"\tnewFile.Meta = copyMeta(f.Meta)\n\treturn &newFile\n}\n\nfunc (WaveFile) UseDBMap() {}\n\ntype FileData struct {\n\tZoneId  string `json:\"zoneid\"`\n\tName    string `json:\"name\"`\n\tPartIdx int    `json:\"partidx\"`\n\tData    []byte `json:\"data\"`\n}\n\nfunc (FileData) UseDBMap() {}\n\n// synchronous (does not interact with the cache)\nfunc (s *FileStore) MakeFile(ctx context.Context, zoneId string, name string, meta wshrpc.FileMeta, opts wshrpc.FileOpts) error {\n\tif opts.MaxSize < 0 {\n\t\treturn fmt.Errorf(\"max size must be non-negative\")\n\t}\n\tif opts.Circular && opts.MaxSize <= 0 {\n\t\treturn fmt.Errorf(\"circular file must have a max size\")\n\t}\n\tif opts.Circular && opts.IJson {\n\t\treturn fmt.Errorf(\"circular file cannot be ijson\")\n\t}\n\tif opts.Circular {\n\t\tif opts.MaxSize%partDataSize != 0 {\n\t\t\topts.MaxSize = (opts.MaxSize/partDataSize + 1) * partDataSize\n\t\t}\n\t}\n\tif opts.IJsonBudget > 0 && !opts.IJson {\n\t\treturn fmt.Errorf(\"ijson budget requires ijson\")\n\t}\n\tif opts.IJsonBudget < 0 {\n\t\treturn fmt.Errorf(\"ijson budget must be non-negative\")\n\t}","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/filestore/blockstore.go#L99-L135","documentation":"FileStore.MakeFile validates FileOpts before creating a file in the block store. A negative MaxSize is nonsensical (it would mean an unbounded-negative capacity), so MakeFile rejects it up front with this error instead of creating a corrupt or unusable file.","triggerScenarios":"Calling MakeFile with wshrpc.FileOpts where opts.MaxSize < 0 — e.g. MaxSize defaulting to -1 in caller code, a subtraction underflow, or a user-supplied size parsed and negated.","commonSituations":"Callers using -1 as a sentinel for 'unlimited' size (MaxSize has no such meaning here); computing MaxSize from a config value minus overhead where the overhead exceeds the value; deserializing options where MaxSize was omitted and becomes a negative default.","solutions":["Fix the caller to pass MaxSize >= 0; use 0 for 'no cap' semantics for non-circular files.","If using -1 as an 'unlimited' sentinel, translate it before calling: if max < 0 { max = 0 }.","Clamp parsed user input: opts.MaxSize = max(0, parsedSize)."],"exampleFix":"// before\nopts := wshrpc.FileOpts{MaxSize: -1} // 'unlimited'\nerr := store.MakeFile(ctx, zoneId, name, meta, opts)\n// after\nmaxSize := int64(-1)\nif maxSize < 0 {\n\tmaxSize = 0\n}\nopts := wshrpc.FileOpts{MaxSize: maxSize}\nerr := store.MakeFile(ctx, zoneId, name, meta, opts)","handlingStrategy":"validation","validationCode":"func validMaxSize(max int64) bool { return max >= 0 }\nif !validMaxSize(opts.MaxSize) {\n\treturn fmt.Errorf(\"caller bug: MaxSize must be >= 0\")\n}","typeGuard":null,"tryCatchPattern":"if err := store.MakeFile(ctx, zoneId, name, meta, opts); err != nil {\n\tif strings.Contains(err.Error(), \"max size must be non-negative\") {\n\t\topts.MaxSize = 0\n\t\terr = store.MakeFile(ctx, zoneId, name, meta, opts)\n\t}\n\tif err != nil {\n\t\treturn err\n\t}\n}","preventionTips":["Never use -1 as an 'unlimited' sentinel for MaxSize; use 0.","Validate FileOpts in your own constructor before calling MakeFile.","Clamp computed/subtracted sizes with max(0, v).","Sanitize user-supplied size inputs before mapping them into opts."],"tags":["validation","filestore","input-validation"],"backgroundTag":"invalid-argument-value","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}