router-for-me/CLIProxyAPI · error

must be a positive integer

Error message

must be a positive integer

What it means

Returned by parseLimit (logs.go:1224) when the `limit` query parameter of a management log endpoint is non-empty but not parseable by strconv.Atoi. The parameter must be a base-10 integer; floats, suffixed numbers, or arbitrary strings are rejected before any log reading happens.

Source

Thrown at internal/api/handlers/management/logs.go:1224

	value := strings.TrimSpace(raw)
	if value == "" {
		return 0
	}
	ts, err := strconv.ParseInt(value, 10, 64)
	if err != nil || ts <= 0 {
		return 0
	}
	return ts
}

func parseLimit(raw string) (int, error) {
	value := strings.TrimSpace(raw)
	if value == "" {
		return 0, nil
	}
	limit, err := strconv.Atoi(value)
	if err != nil {
		return 0, fmt.Errorf("must be a positive integer")
	}
	if limit <= 0 {
		return 0, fmt.Errorf("must be greater than zero")
	}
	return limit, nil
}

func parseTimestamp(line string) int64 {
	if strings.HasPrefix(line, "[") {
		line = line[1:]
	}
	if len(line) < 19 {
		return 0
	}
	candidate := line[:19]
	t, err := time.ParseInLocation("2006-01-02 15:04:05", candidate, time.Local)
	if err != nil {
		return 0

View on GitHub (pinned to 78f0c4079e)

Solutions

  1. Send a plain integer: /management/logs?limit=100
  2. Omit the parameter entirely if you want the server default (empty string is accepted as no limit)
  3. Fix the client to validate limit is an integer before building the URL

Example fix

# before
curl -H "Authorization: Bearer $KEY" 'http://127.0.0.1:8000/management/logs?limit=10.5'

# after
curl -H "Authorization: Bearer $KEY" 'http://127.0.0.1:8000/management/logs?limit=10'
Defensive patterns

Strategy: validation

Validate before calling

// Client-side guard before building the URL.
if limitParam != "" {
	if _, err := strconv.Atoi(strings.TrimSpace(limitParam)); err != nil {
		limitParam = "" // drop invalid value, use server default
	}
}

Type guard

function isValidLimit(raw string) bool {
	if strings.TrimSpace(raw) === "") return true;
	return /^-?\d+$/.test(raw.trim()) && parseInt(raw.trim(), 10) > 0;
}

Prevention

When it happens

Trigger: GET /management/logs?limit=10.5, ?limit=all, ?limit=1e3, or a limit containing whitespace/signs that Atoi rejects. Any log-reading endpoint that accepts `limit` funnels through parseLimit (logs.go:78).

Common situations: Dashboards sending UI defaults like 'all' or 'None' as limit; copy-pasted URLs with locale-formatted numbers (1,000); query builders that serialize floats as strings.

Related errors


AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15). Data as JSON: /api/errors/5512a1cda47b40e1. Report an issue: GitHub.