langchain-ai/deepagents · error · HITLIterationLimitError

{message}

Error message

{message}

What it means

`_raise_hitl_iteration_limit` raises `HITLIterationLimitError` when the headless (non-interactive) agent loop exceeds its bounded number of human-in-the-loop turns. Because headless mode has no human to keep answering permission prompts, the loop is capped to prevent an infinite permission request/response cycle; exceeding the cap aborts the run with this error.

Source

Thrown at libs/code/deepagents_code/client/non_interactive.py:138

        HookNoticeCallback,
        HookNoticeSeverity,
    )
    from deepagents_code.hooks.transcript import TranscriptRecorder

logger = logging.getLogger(__name__)


class HITLIterationLimitError(RuntimeError):
    """Raised when the HITL interrupt loop exceeds `_MAX_HITL_ITERATIONS` rounds."""


def _raise_hitl_iteration_limit(message: str) -> NoReturn:
    """Raise the bounded-turn failure outside the stream-control try block.

    Raises:
        HITLIterationLimitError: Always, with the supplied message.
    """
    raise HITLIterationLimitError(message)


def _raise_client_hook_stop(message: str) -> NoReturn:
    from deepagents_code.hooks.client_lifecycle import ClientHookStopError

    raise ClientHookStopError(message)


_HITL_REQUEST_ADAPTER = TypeAdapter(HITLRequest)

_STREAM_CHUNK_LENGTH = 3
"""Expected element counts for the tuples emitted by agent.astream.

Stream chunks are 3-tuples: (namespace, stream_mode, data).
"""

_MESSAGE_DATA_LENGTH = 2
"""Message-mode data is a 2-tuple: (message_obj, metadata)."""

View on GitHub (pinned to a1af029e6e)

Solutions

  1. Adjust the permission configuration (e.g. `shell.allow_list`) so recurring tool calls are auto-approved and stop consuming HITL turns.
  2. Raise the HITL iteration limit option if the task genuinely needs more approval rounds.
  3. Re-run non-interactively with a permission mode that auto-allows the tools the task needs (e.g. accept-edits/bypass where policy permits).
  4. Split the task into smaller runs so each stays within the turn budget.

Example fix

// before: command not allow-listed, consumes HITL turns each run
subprocess.run(["make", "lint"])
// after: pre-approve in config so no HITL turns are used
# config: shell.allow_list = ["make *"]
subprocess.run(["make", "lint"])
Defensive patterns

Strategy: validation

Validate before calling

from deepagents_code.config_manifest import get_option
from deepagents_code.configuration.resolver import get_config_resolver
option = get_option("shell.allow_list")
resolved = get_config_resolver().get(option)
# ensure the commands your task needs are allow-listed before the run
assert resolved.value, "shell.allow_list must cover task commands to avoid HITL turn exhaustion"

Try / catch

from deepagents_code.client.non_interactive import HITLIterationLimitError
try:
    run_non_interactive(task)
except HITLIterationLimitError as exc:
    print(f"hitl budget exhausted: {exc}")  # loosen permissions or raise limit and retry

Prevention

When it happens

Trigger: Calling `run_non_interactive` with a task that repeatedly triggers HITL permission requests (e.g. many tool calls requiring approval from the allow-list resolution) such that `_run_agent_loop` consumes the maximum allowed HITL iterations without completing.

Common situations: Automated CI/headless runs where a shell command or file edit is not covered by `shell.allow_list` or other permission rules, causing repeated permission interrupts; misconfigured permission rules that force every tool call into the HITL path; tasks that legitimately need more approval rounds than the configured limit.

Related errors


AI-assisted analysis of langchain-ai/deepagents@a1af029e6e (2026-08-29). Data as JSON: /api/errors/79214d9312143d48. Report an issue: GitHub.