alibaba/open-code-review · error

main_task.messages must not be empty

Error message

main_task.messages must not be empty

What it means

Template.Validate requires the main task conversation to contain at least one message; a Template with no MAIN_TASK messages has nothing to send to the LLM, so Validate returns 'main_task.messages must not be empty'. This is thrown for programmatically built templates or manifests where MAIN_TASK.messages is an empty array or the field is absent.

Source

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

	}
	if t.ProjectSummaryTask != nil {
		applyLanguage(t.ProjectSummaryTask, instruction)
	}
	applyLanguage(&t.MemoryCompressionTask, instruction)
}

func (t *Template) Validate() error {
	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
}

View on GitHub (pinned to 5cf97d0d15)

Solutions

  1. Add at least one message (typically a system prompt referencing a promptFile) to MAIN_TASK in task_template.json and rebuild
  2. When constructing Template in Go, populate MainTask.Messages from resolveConversation or literal ChatMessage values before Validate
  3. Guard any script that generates the manifest to fail if it would emit an empty messages array
  4. Run the package tests (TestValidate_*) after editing to confirm the manifest still validates

Example fix

// before (task_template.json)
{"MAIN_TASK": {"messages": []}}
// after
{"MAIN_TASK": {"messages": [{"role": "system", "promptFile": "prompts/main_system.md"}]}}
Defensive patterns

Strategy: validation

Validate before calling

if len(tpl.MainTask.Messages) == 0 {
	return fmt.Errorf("MainTask must have at least one message before Validate")
}
if err := tpl.Validate(); err != nil { return err }

Type guard

func hasMainTaskMessages(t *template.Template) bool {
	return t != nil && len(t.MainTask.Messages) > 0
}

Try / catch

if err := tpl.Validate(); err != nil {
	if strings.Contains(err.Error(), "main_task.messages must not be empty") {
		return fmt.Errorf("template was built without MAIN_TASK messages; populate MainTask via resolveConversation or LoadDefault")
	}
	return err
}

Prevention

When it happens

Trigger: Calling (*Template).Validate() with len(t.MainTask.Messages) == 0 — e.g. task_template.json with "MAIN_TASK": {"messages": []}, a template literal with MainTask unset, or resolveConversation failing silently upstream is impossible here (it errors), so this is purely an emptiness check.

Common situations: Authoring a custom template manifest and forgetting to add messages; truncating the JSON during editing; constructing a Template in tests/injection code and skipping MainTask; a generation script that emitted an empty messages array.

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/c38bd498bdd913dd. Report an issue: GitHub.