wavetermdev/waveterm · error

count must be positive

Error message

count must be positive

What it means

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.

Source

Thrown at pkg/aiusechat/tools_term.go:76

		result.Count = DefaultCount
		return result, nil
	}

	inputBytes, err := json.Marshal(input)
	if err != nil {
		return nil, fmt.Errorf("failed to marshal input: %w", err)
	}

	if err := json.Unmarshal(inputBytes, result); err != nil {
		return nil, fmt.Errorf("failed to unmarshal input: %w", err)
	}

	if result.Count == 0 {
		result.Count = DefaultCount
	}

	if result.Count < 0 {
		return nil, fmt.Errorf("count must be positive")
	}

	result.Count = min(result.Count, MaxCount)

	return result, nil
}

func getTermScrollbackOutput(tabId string, widgetId string, rpcData wshrpc.CommandTermGetScrollbackLinesData) (*TermGetScrollbackToolOutput, error) {
	ctx, cancelFn := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancelFn()

	fullBlockId, err := wcore.ResolveBlockIdFromPrefix(ctx, tabId, widgetId)
	if err != nil {
		return nil, err
	}

	rpcClient := wshclient.GetBareRpcClient()
	result, err := wshclient.TermGetScrollbackLinesCommand(

View on GitHub (pinned to a4447c1563)

Solutions

  1. Pass count >= 1, or omit count entirely to get the default of 200
  2. If you want 'the last N lines', use line_start: 0 with count: N, not a negative count
  3. Clamp user/model-supplied counts to [1, 1000] before invoking the tool
  4. If you believe 0 should be an error or negative counts should wrap, adjust the validation — but as a caller, never send negatives

Example fix

// before
{"widget_id": "b1a2c3d4", "count": -10}
// after
{"widget_id": "b1a2c3d4", "line_start": 0, "count": 10}
Defensive patterns

Strategy: validation

Validate before calling

if count, ok := inputMap["count"]; ok {
    if n, ok := count.(float64); ok && (n < 1 || n != float64(int(n))) {
        return fmt.Errorf("count must be an integer >= 1")
    }
}

Type guard

func validCount(n int) bool { return n >= 1 && n <= 1000 }

Try / catch

parsed, err := parseTermGetScrollbackInput(input)
if err != nil {
    if strings.Contains(err.Error(), "count must be positive") {
        return nil, fmt.Errorf("invalid tool argument: send count >= 1 or omit it (default 200)")
    }
    return nil, err
}

Prevention

When it happens

Trigger: term_get_scrollback called with {"count": -1} (or any negative integer) in the tool arguments.

Common situations: 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.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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