# Understanding Max Loop Count Behavior in UI-TARS Desktop: Preventing Premature Termination

> Learn how to prevent premature termination by understanding max loop count behavior in UI-TARS Desktop. Override settings and manage abort signals for uninterrupted agent execution.

- Repository: [Bytedance Inc./UI-TARS-desktop](https://github.com/bytedance/UI-TARS-desktop)
- Tags: deep-dive
- Published: 2026-05-10

---

**The max loop count in UI-TARS Desktop defaults to 100 iterations and halts the agent with a `REACH_MAXLOOP_ERROR` when exceeded, but you can prevent premature termination by overriding `maxLoopCount` in the configuration, restricting the `MAX_LOOP` action space, and properly managing abort signals.**

The `GUIAgent` class in the `bytedance/UI-TARS-desktop` repository executes a continuous perception-action loop that captures screenshots, queries a vision-language model, and executes predicted actions. To prevent infinite execution, this loop is bounded by a **max loop count** ceiling that terminates the agent when exceeded. Understanding how this limit works—and the conditions that can trigger early termination—is critical for building stable automation agents.

## What Is the Max Loop Count?

The max loop count is a safety mechanism that hard-caps the number of iterations the agent can execute. The default value is defined in [`packages/ui-tars/shared/src/constants/vlm.ts`](https://github.com/bytedance/UI-TARS-desktop/blob/main/packages/ui-tars/shared/src/constants/vlm.ts):

```ts
export const MAX_LOOP_COUNT = 100;

```

When instantiating `GUIAgent`, you can override this default via the `maxLoopCount` property in `GUIAgentConfig`. The constructor extracts this value with a fallback to the constant:

```ts
const {
  // ...
  maxLoopCount = MAX_LOOP_COUNT,
} = this.config;

```

*Source:* [`packages/ui-tars/sdk/src/GUIAgent.ts`](https://github.com/bytedance/UI-TARS-desktop/blob/main/packages/ui-tars/sdk/src/GUIAgent.ts) (lines 76-78)

## How the Loop Counter Works

Inside the agent's main execution loop, the counter `loopCnt` starts at zero and increments once per successful iteration immediately after capturing a screenshot:

```ts
loopCnt += 1;

```

*Source:* [`packages/ui-tars/sdk/src/GUIAgent.ts`](https://github.com/bytedance/UI-TARS-desktop/blob/main/packages/ui-tars/sdk/src/GUIAgent.ts) (line 182)

Before processing each iteration, the agent checks if the counter has reached the configured limit:

```ts
if (loopCnt >= maxLoopCount) {
  Object.assign(data, {
    status: StatusEnum.ERROR,
    error: this.guiAgentErrorParser(
      ErrorStatusEnum.REACH_MAXLOOP_ERROR,
    ),
  });
  break;
}

```

*Source:* [`packages/ui-tars/sdk/src/GUIAgent.ts`](https://github.com/bytedance/UI-TARS-desktop/blob/main/packages/ui-tars/sdk/src/GUIAgent.ts) (lines 162-170)

When this condition triggers, the agent immediately exits with a `REACH_MAXLOOP_ERROR` status.

## Causes of Premature Termination

Agents can terminate before hitting the numeric limit due to specific internal actions, external signals, or environmental failures.

### The Internal MAX_LOOP Action

The model may deliberately emit the internal action `MAX_LOOP`, which triggers immediate termination regardless of the counter value:

```ts
else if (actionType === INTERNAL_ACTION_SPACES_ENUM.MAX_LOOP) {
  Object.assign(data, {
    status: StatusEnum.ERROR,
    error: this.guiAgentErrorParser(
      ErrorStatusEnum.REACH_MAXLOOP_ERROR,
    ),
  });
  break;
}

```

*Source:* [`packages/ui-tars/sdk/src/GUIAgent.ts`](https://github.com/bytedance/UI-TARS-desktop/blob/main/packages/ui-tars/sdk/src/GUIAgent.ts) (lines 66-74)

This provides the model a mechanism to signal it cannot complete the task, but it can cause unexpected failures if the model incorrectly predicts this token.

### External Stop Signals

The loop monitors several external termination conditions:

```ts
if (this.isStopped ||
    (data.status !== StatusEnum.RUNNING && data.status !== StatusEnum.PAUSE) ||
    signal?.aborted) {
  signal?.aborted && (data.status = StatusEnum.USER_STOPPED);
  break;
}

```

*Source:* [`packages/ui-tars/sdk/src/GUIAgent.ts`](https://github.com/bytedance/UI-TARS-desktop/blob/main/packages/ui-tars/sdk/src/GUIAgent.ts) (lines 151-160)

These include explicit calls to `guiAgent.stop()`, status changes to non-running states, or AbortSignal abortion.

### Screenshot Failure Exhaustion

Persistent screenshot failures trigger early exit via `MAX_SNAPSHOT_ERR_CNT`:

```ts
if (snapshotErrCnt >= MAX_SNAPSHOT_ERR_CNT) { 
  // ... error handling and break
}

```

*Source:* [`packages/ui-tars/sdk/src/GUIAgent.ts`](https://github.com/bytedance/UI-TARS-desktop/blob/main/packages/ui-tars/sdk/src/GUIAgent.ts) (lines 172-179)

## Preventing Premature Termination

### Increase the Loop Ceiling

For long-running tasks, pass a higher `maxLoopCount` value when constructing the agent:

```ts
const agent = new GUIAgent({
  operator,
  model,
  maxLoopCount: 500,  // Allow up to 500 iterations
  // ... other config
});

```

This configuration is defined in [`packages/ui-tars/sdk/src/types.ts`](https://github.com/bytedance/UI-TARS-desktop/blob/main/packages/ui-tars/sdk/src/types.ts) as part of the `GUIAgentConfig` interface.

### Restrict Action Spaces

Prevent the model from emitting the `MAX_LOOP` token by excluding it from your operator's available action spaces:

```ts
import { INTERNAL_ACTION_SPACES_ENUM } from '@ui-tars/sdk';

class MyOperator extends Operator {
  static MANUAL = {
    ACTION_SPACES: [
      INTERNAL_ACTION_SPACES_ENUM.CALL_USER,
      INTERNAL_ACTION_SPACES_ENUM.FINISHED,
      // Deliberately omit INTERNAL_ACTION_SPACES_ENUM.MAX_LOOP
    ],
  };
}

```

*Key definition:* [`packages/ui-tars/sdk/src/constants.ts`](https://github.com/bytedance/UI-TARS-desktop/blob/main/packages/ui-tars/sdk/src/constants.ts)

### Stabilize Abort Handling

Maintain the `AbortSignal` reference for the duration of the task. Only call `controller.abort()` or `agent.stop()` when intentional cancellation is required:

```ts
const controller = new AbortController();

const agent = new GUIAgent({
  operator,
  model,
  signal: controller.signal,
});

// To stop intentionally:
controller.abort(); // Sets StatusEnum.USER_STOPPED, not a max-loop error

```

### Handle Snapshot Errors

Provide a stable display environment to prevent intermittent screenshot failures. If occasional failures are expected in your environment, consider adjusting `MAX_SNAPSHOT_ERR_CNT` if your SDK version exposes this configuration.

## Implementation Examples

### Configuring a Higher Iteration Limit

```ts
import { GUIAgent } from '@ui-tars/sdk';

const agent = new GUIAgent({
  operator: myOperator,
  model: myModel,
  logger: console,
  maxLoopCount: 300,  // Override default 100
});

await agent.run('Navigate to the settings page and modify preferences');

```

### Filtering the MAX_LOOP Action

```ts
import { Operator } from '@ui-tars/sdk';
import { INTERNAL_ACTION_SPACES_ENUM } from '@ui-tars/sdk/constants';

class SafeOperator extends Operator {
  static MANUAL = {
    ACTION_SPACES: [
      INTERNAL_ACTION_SPACES_ENUM.CALL_USER,
      INTERNAL_ACTION_SPACES_ENUM.FINISHED,
    ],
  };
  
  // ... operator implementation
}

```

By not exposing `MAX_LOOP` in the action space, you eliminate the model's ability to trigger premature termination via that path.

## Summary

- The default **max loop count is 100** iterations, defined in [`packages/ui-tars/shared/src/constants/vlm.ts`](https://github.com/bytedance/UI-TARS-desktop/blob/main/packages/ui-tars/shared/src/constants/vlm.ts) and enforced in [`GUIAgent.ts`](https://github.com/bytedance/UI-TARS-desktop/blob/main/GUIAgent.ts).
- The counter increments once per iteration and triggers `REACH_MAXLOOP_ERROR` when the ceiling is reached.
- **Premature termination** can occur via the internal `MAX_LOOP` action, abort signals, or screenshot failure limits.
- **Mitigation strategies** include overriding `maxLoopCount` in the config, removing `MAX_LOOP` from action spaces, and ensuring stable screenshot capture environments.

## Frequently Asked Questions

### What is the default max loop count in UI-TARS Desktop?

The default limit is **100 iterations**, defined as `MAX_LOOP_COUNT` in [`packages/ui-tars/shared/src/constants/vlm.ts`](https://github.com/bytedance/UI-TARS-desktop/blob/main/packages/ui-tars/shared/src/constants/vlm.ts). This value is used when no override is provided in the `GUIAgentConfig`.

### How do I increase the max loop count limit?

Pass a custom `maxLoopCount` value when constructing the `GUIAgent` instance. For example, `new GUIAgent({ ..., maxLoopCount: 500 })` allows up to 500 iterations before triggering the error state.

### Why does my agent stop with REACH_MAXLOOP_ERROR before completing 100 iterations?

This occurs when the vision-language model emits the internal `MAX_LOOP` action, or when the agent encounters `MAX_SNAPSHOT_ERR_CNT` screenshot failures. Check your operator's action spaces configuration to ensure `MAX_LOOP` is not exposed to the model, and verify display stability to prevent snapshot errors.

### Can I disable the max loop count protection entirely?

No, the ceiling cannot be disabled entirely—it is a required safety parameter in the `GUIAgent` logic. However, you can set an arbitrarily high value (e.g., `999999`) via `maxLoopCount` in the configuration to effectively remove practical limits while maintaining the safety check.