alibaba/open-code-review · error

scan: max_tokens must be positive

Error message

scan: max_tokens must be positive

What it means

ScanTemplate.Validate performs the same minimum checks as Template.Validate but for the scan template, prefixing messages with 'scan: ' so the failing template kind is identifiable. 'scan: max_tokens must be positive' means the scan template's MaxTokens is zero or negative, so the scan review request cannot be budgeted.

Source

Thrown at internal/config/template/template.go:331

	if t.MaxTokens <= 0 {
		return fmt.Errorf("max_tokens must be positive")
	}
	if t.MaxToolRequestTimes <= 0 {
		return fmt.Errorf("max_tool_request_times must be positive")
	}
	if t.MaxReviewRounds < 0 {
		return fmt.Errorf("max_review_rounds must not be negative")
	}
	if len(t.MainTask.Messages) == 0 {
		return fmt.Errorf("main_task.messages must not be empty")
	}
	return nil
}

// Validate checks that a ScanTemplate has the minimum fields populated.
func (t *ScanTemplate) Validate() error {
	if t.MaxTokens <= 0 {
		return fmt.Errorf("scan: max_tokens must be positive")
	}
	if t.MaxToolRequestTimes <= 0 {
		return fmt.Errorf("scan: max_tool_request_times must be positive")
	}
	if len(t.MainTask.Messages) == 0 {
		return fmt.Errorf("scan: main_task.messages must not be empty")
	}
	return nil
}

// LlmConversation is a preset prompt with settings.
type LlmConversation struct {
	Messages []ChatMessage `json:"messages"`
}

// ChatMessage represents a single message in a conversation.
type ChatMessage struct {
	Role    string `json:"role"`

View on GitHub (pinned to 5cf97d0d15)

Solutions

  1. Set MaxTokens to a positive value on the ScanTemplate before Validate
  2. Add "MAX_TOKENS": <n> (n > 0) to scan_template.json and rebuild if the value comes from the embedded manifest
  3. Compare against the shipped default scan_template.json to ensure no required numeric fields were dropped during customization
  4. Call Validate immediately after LoadScanDefault/manifest copy so errors surface before executeScan issues any request

Example fix

// before (scan_template.json)
{"MAX_TOOL_REQUEST_TIMES": 5, "MAIN_TASK": {...}}
// after
{"MAX_TOKENS": 8192, "MAX_TOOL_REQUEST_TIMES": 5, "MAIN_TASK": {...}}
Defensive patterns

Strategy: validation

Validate before calling

if stpl.MaxTokens <= 0 {
	return fmt.Errorf("scan MaxTokens must be > 0 before Validate, got %d", stpl.MaxTokens)
}
if err := stpl.Validate(); err != nil { return err }

Try / catch

if err := stpl.Validate(); err != nil {
	if strings.Contains(err.Error(), "scan: max_tokens must be positive") {
		stpl.MaxTokens = 8192
		err = stpl.Validate()
	}
	if err != nil { return err }
}

Prevention

When it happens

Trigger: Calling (*ScanTemplate).Validate() with t.MaxTokens <= 0 — typically a scan_template.json embedded manifest missing MAX_TOKENS or a hand-built ScanTemplate left at its zero value, e.g. before executeScan runs.

Common situations: Customizing scan_template.json and dropping MAX_TOKENS; constructing a ScanTemplate in tests (TestLoadScanDefault_*/TestRunScanPreview paths) without setting the token budget; copying fields from task_template.json to a ScanTemplate while missing the scan-specific keys.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


AI-assisted analysis of alibaba/open-code-review@5cf97d0d15 (2026-09-02). Data as JSON: /api/errors/3684e65282e69889. Report an issue: GitHub.