{"record":{"id":"cddc2083d4c2131b","repo":"wavetermdev/waveterm","slug":"count-must-be-positive","errorCode":null,"errorMessage":"count must be positive","messagePattern":"count must be positive","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/aiusechat/tools_term.go","lineNumber":76,"sourceCode":"\t\tresult.Count = DefaultCount\n\t\treturn result, nil\n\t}\n\n\tinputBytes, err := json.Marshal(input)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to marshal input: %w\", err)\n\t}\n\n\tif err := json.Unmarshal(inputBytes, result); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to unmarshal input: %w\", err)\n\t}\n\n\tif result.Count == 0 {\n\t\tresult.Count = DefaultCount\n\t}\n\n\tif result.Count < 0 {\n\t\treturn nil, fmt.Errorf(\"count must be positive\")\n\t}\n\n\tresult.Count = min(result.Count, MaxCount)\n\n\treturn result, nil\n}\n\nfunc getTermScrollbackOutput(tabId string, widgetId string, rpcData wshrpc.CommandTermGetScrollbackLinesData) (*TermGetScrollbackToolOutput, error) {\n\tctx, cancelFn := context.WithTimeout(context.Background(), 5*time.Second)\n\tdefer cancelFn()\n\n\tfullBlockId, err := wcore.ResolveBlockIdFromPrefix(ctx, tabId, widgetId)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\trpcClient := wshclient.GetBareRpcClient()\n\tresult, err := wshclient.TermGetScrollbackLinesCommand(","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/aiusechat/tools_term.go#L58-L94","documentation":"parseTermGetScrollbackInput rejects a negative count with this sentinel error after defaulting a zero count to 200 and clamping to MaxCount (1000). Note the message says 'must be positive' but the check is result.Count < 0, so only negative values trigger it — 0 is treated as 'use default'. It guards the scrollback RPC against nonsensical line counts.","triggerScenarios":"term_get_scrollback called with {\"count\": -1} (or any negative integer) in the tool arguments.","commonSituations":"AI model hallucinating a negative count (e.g. count: -10 intending 'last 10 lines'); off-by-sign logic in code that programmatically builds tool input; confusing line indexing direction (0 = most recent) with negative offsets.","solutions":["Pass count >= 1, or omit count entirely to get the default of 200","If you want 'the last N lines', use line_start: 0 with count: N, not a negative count","Clamp user/model-supplied counts to [1, 1000] before invoking the tool","If you believe 0 should be an error or negative counts should wrap, adjust the validation — but as a caller, never send negatives"],"exampleFix":"// before\n{\"widget_id\": \"b1a2c3d4\", \"count\": -10}\n// after\n{\"widget_id\": \"b1a2c3d4\", \"line_start\": 0, \"count\": 10}","handlingStrategy":"validation","validationCode":"if count, ok := inputMap[\"count\"]; ok {\n    if n, ok := count.(float64); ok && (n < 1 || n != float64(int(n))) {\n        return fmt.Errorf(\"count must be an integer >= 1\")\n    }\n}","typeGuard":"func validCount(n int) bool { return n >= 1 && n <= 1000 }","tryCatchPattern":"parsed, err := parseTermGetScrollbackInput(input)\nif err != nil {\n    if strings.Contains(err.Error(), \"count must be positive\") {\n        return nil, fmt.Errorf(\"invalid tool argument: send count >= 1 or omit it (default 200)\")\n    }\n    return nil, err\n}","preventionTips":["Enforce InputSchema minimum: 1 for count before invoking the tool","To page backward, increase line_start, never use negative count","Clamp client-side to [1, 1000] since the tool clamps to MaxCount anyway"],"tags":["validation","tool-input","terminal","wave"],"backgroundTag":"invalid-argument-value","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}