◉GEMINI LABJP
●ARGON — gemini-4-argon is generally available as of 10/13, aimed at complex coding, agents, math and science●COMPUTER — Computer Use is now generally available in the Interactions and GenerateContent APIs (10/30)●NANO — gemini-nano-banana-2.1 is GA (10/06). gemini-3.1-flash-image is deprecated with no shutdown date yet●CLI — Gemini API CLI (gemini-api) is out in beta (10/27): a zero-dependency client for agents and CI●STORE — New paid projects now save Generate Content requests by default (store on) as of 10/26●NEW — Stop Re-Reading Every Crash Report: Gre…●ARGON — gemini-4-argon is generally available as of 10/13, aimed at complex coding, agents, math and science●COMPUTER — Computer Use is now generally available in the Interactions and GenerateContent APIs (10/30)●NANO — gemini-nano-banana-2.1 is GA (10/06). gemini-3.1-flash-image is deprecated with no shutdown date yet●CLI — Gemini API CLI (gemini-api) is out in beta (10/27): a zero-dependency client for agents and CI●STORE — New paid projects now save Generate Content requests by default (store on) as of 10/26●NEW — Stop Re-Reading Every Crash Report: Gre…
Articles/Advanced
⬡ Advanced/2026-10-31Intermediate

When Computer Use Ends After a Few Steps — Finding the Reason Among Four Exits

When Gemini API Computer Use stops after a few steps with no error, sort the cause into four exits that follow the official loop: no function_call, turn_limit, safety_decision, or a bad function_result. Includes a short script that logs the exit reason in one line.

Gemini API255Computer UseInteractions API8Troubleshooting9Browser Automation

Picture an evening spent watching Gemini drive a browser on your screen. A search page opens, text lands in the input field, and just before the button should be pressed, everything stops. No error appears. Your script prints a normal exit.

On October 30, 2026, the Gemini API changelog added an entry titled "Computer Use generally available (GA)". The Computer Use tool is now GA across both the Interactions API and the GenerateContent API. Whether you started in preview or are only trying it now, this "it just ended" moment is likely to come up for more people.

What I'd like to say first is that, quite often, the loop didn't stop. It ended because it was written to end there. Before doubting the model, you can start by counting the loop's exits.

Where the official loop is written to end

The official Computer Use walkthrough follows roughly this shape:

  1. Send the prompt, an initial screenshot, and the tool config to client.interactions.create
  2. Read the returned function_call steps and run each action in your own environment (the examples use Playwright)
  3. Take a fresh screenshot and send it back as a function_result, with previous_interaction_id
  4. Repeat until the model stops returning function_call

You enable the tool with something like tools=[{"type": "computer_use", "environment": "browser"}], and environment can be browser, mobile, or desktop.

One thing is easy to miss here. The signal for "done" is not an error. It is simply that no function_call came back. A normal finish and an interruption look the same. The official example also caps the loop with turn_limit = 5. If you copy that number as-is, the loop ends at step five without a word.

Log the four exits so you can tell them apart

As far as I can count from the official description, a loop can end for four reasons.

ExitWhat happenedClue in your logs
1. The model finishedA response arrived with no function_call. The model considers the task done, or cannot continueThe last response text reports completion or says what it couldn't do
2. Turn capYour own turn_limit was reachedThe loop count equals the cap
3. Waiting on confirmationA safety_decision of require_confirmation arrived, and confirmation was declined or the code abortedThe last function_call carries a safety_decision whose decision is require_confirmation
4. A bad returnfunction_result wasn't sent, previous_interaction_id wasn't chained, or the screenshot was empty or in the wrong formatAn exception in the log, or a break just before the next create call

Writing one line at the end of the loop is enough to tell them apart. The skeleton below borrows the official structure. capture_screenshot and execute_action are yours to supply (Playwright, for example), and the details of the API call should follow the official sample.

# Skeleton: always leave one line saying why the loop ended
TURN_LIMIT = 20  # the official example uses 5; don't carry a prototype cap into production
 
exit_reason = None
prev_id = None
turn = 0
 
while True:
    turn += 1
    if turn > TURN_LIMIT:
        exit_reason = f"turn_limit({TURN_LIMIT})"
        break
 
    try:
        interaction = send_to_model(prev_id)  # your wrapper around create
    except Exception as e:
        exit_reason = f"api_error:{type(e).__name__}"
        break
    prev_id = interaction.id
 
    calls = [s for s in interaction.steps if s.type == "function_call"]
    if not calls:
        exit_reason = "model_finished_no_function_call"
        break
 
    results = []
    for call in calls:
        decision = getattr(call, "safety_decision", None)
        if decision and decision.decision == "require_confirmation":
            if not ask_user(decision.explanation):
                exit_reason = "safety_confirmation_declined"
                break
        results.append(execute_action(call))  # return a screenshot and the URL too
    if exit_reason:
        break
 
print(f"[computer_use] exit={exit_reason} turns={turn}")

The point of this code is that no path leaves with exit_reason empty. Once every break has a name, the next morning's log tells you which exit it was, and that decides what to look at next.

Exit four looks like a stop, but the loop could have continued

Exit four is the hardest to spot. The screen stops moving and nothing is raised. From the official text I could read three things to get right when returning results:

  • Return the current URL and a PNG image in function_result (base64, with mime_type set to image/png)
  • Pass previous_interaction_id on the follow-up call
  • Attach a screenshot to the very first request too

On coordinates, the official description wavers a little. One example converts coordinates in the 0 to 999 range into pixels, while another passage describes pixel predictions scaled to the screen. I couldn't settle which is correct from that single page. If clicks always land slightly off and nothing happens before the loop ends, whether you convert is worth suspecting.

The example's typing handler also uses Meta+A, which is the macOS way to select all. On Windows or Linux browsers the key differs, so old text may remain in the field and the model may conclude it couldn't type. That path is my guess, not something the docs state.

Exit three, waiting on confirmation, is a correct way to stop

When safety_decision arrives with require_confirmation, you ask the user, and if they agree, set safety_acknowledgement on the result and continue. The docs describe safety overrides as only a preference and say you should always implement safety_decision handling.

The safety policy categories include financial transactions, sensitive data modification, communication tools, account creation, data modification, consent management, and legal agreements. An action that submits something in a store console is likely to fall into one of them. As an indie developer who would like to hand some console chores to a browser agent, I read this stop as something worth keeping rather than an inconvenience.

If the reason turns out to be exit three, don't fix the loop; fix the side that shows the confirmation. If you run unattended, for instance overnight, the cleaner line is not to delegate that action at all.

A small preparation before you start

The docs warn that Computer Use may contain errors and security vulnerabilities. They recommend close supervision, not using it for critical decisions, sensitive data, or irreversible actions, and running it in a sandboxed VM or container. Prompt injection detection (enable_prompt_injection_detection) is off by default and requires Gemini 3.5 Flash-Lite or later. The model name in the official example is gemini-3.8-flash.

I'd start with read-only work that sends nothing outside, and widen the scope only once the exit reason reads clearly in a single line. For problems where the agent acts on a stale screen, see Gemini Computer Use quietly acting on a stale screen, and for recovery design after failures, Self-healing architecture for Gemini Computer Use. This article sits one step earlier: why it ended at all.

Where I'd draw the line

What stays with me after writing this is that automation failures linger less because "it didn't work" and more because "I couldn't read why". In a prototype, ending after five steps barely registers. Forget the cap and move it into operation, and you spend the night just hunting for the reason.

I won't hand over a loop whose ending I can't read in one line. That's the line I've set for myself after this check.

A good first step is to add one exit_reason line at the end of your own loop, so that the next time it stops, the exit has a name.

Share

Thank You for Reading

Gemini Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • ✦Copy-paste ready implementation code
  • ✦New advanced guides published daily
  • ✦$5/mo or $10 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

⬡ Advanced2026-09-24
I Stopped Asking Gemini 'Is This Right?' and Started Hiding My Answer Instead
Ask Gemini to confirm a label you already chose and it tends to agree. Here is why I compared three ways of asking, chose blind re-classification, how my answer still leaked in, and the routing code that sends only disagreements to a human.
⬡ Advanced2026-09-14
When BLOCK_NONE Changes Nothing: Telling Adjustable Gemini Blocks from the Ones You Can't Move
Some safety blocks go away when you loosen a threshold. Others never will. Here is how to read the response and decide which kind you are looking at before you touch a single setting.
⬡ Advanced2026-09-05
Two Kinds of Video Questions: Why I Send "Find It" and "Prove It Isn't There" Down Separate Paths
Agentic video understanding lets the model decide which parts of a video to watch. That works beautifully for finding things, and it quietly breaks when you need to prove something never appears. Here is how I split my questions, and the coverage check I now run first.