Skip to Content
IssuesKeyword Researcher: maxTurnsPerRun Too Low — All Jobs Fail

Keyword Researcher: maxTurnsPerRun Too Low — All Jobs Fail

Status: Fixed Severity: High — all keyword research deliverables fail; keyword groups never created File: packages/agents/src/workers/keyword-researcher.worker.ts Observed: 2026-05-06 00:36 onwards (all keyword-researcher jobs fail consistently)

Symptom

ERROR [content-worker] keyword-researcher job failed Error: Reached maximum turns per run

Fires on every keyword-researcher job. No keyword groups or keywords are written to the DB. The activity ends in status: "failed".

Root Cause

keyword-researcher.worker.ts calls createContentWorker("keyword-researcher", { ... }) without specifying maxTurnsPerRun. The createContentWorker factory defaults to:

maxTurnsPerRun: options?.maxTurnsPerRun ?? 3, // content.worker.ts default

The keyword researcher generates a large JSON object with multiple keyword groups, each containing 8-15 keywords with metadata (searchVolume, difficulty, intent, category). For a typical tenant with 5-10 groups, the output can be 4-6K tokens — too large to fit in a single turn when combined with the full system prompt and client context.

Claude hits the 3-turn limit while still generating the JSON, causing truncation and a “Reached maximum turns per run” error before the output is complete enough to parse.

This differs from pure-text workers (blog, social) where maxTurnsPerRun: 1 is correct. The keyword researcher’s structured JSON output is simply larger.

Fix Applied

packages/agents/src/workers/keyword-researcher.worker.ts:

const { start, stop } = createContentWorker("keyword-researcher", { creditType: "keyword_cluster", postProcess, skipAutoApprove: true, maxTurnsPerRun: 8, // JSON output spans many keyword groups; needs more turns than the default 3 });

Requires agents server restart to take effect.

Why 8 Turns

  • Each Claude turn produces ~1-2K tokens of JSON
  • Full keyword output is 4-8K tokens (5-10 groups x 8-15 keywords each)
  • 8 turns provides enough headroom with a safety margin
  • allowedTools: [] (inherited default) means all turns are used for output only, no tool calls

© 2026 Leadmetrics — Internal use only