OpenAI Assistants API Run Stuck in \"in_progress\": Causes, Diagnosis, and Fixes

OpenAI Assistants API
API troubleshooting
in_progress run
tool calling
retry handling

When you start a run with the Assistants API, you expect it to move through the lifecycle: queued → in_progress → completed (or failed/expired). In practice, many developers see the run linger forever in the in_progress state, making the API unusable for their applications. This guide explains why that happens, how to confirm what’s going on, and what you can do to recover and prevent future stalls.

Recognizing the Symptom

A run that never leaves in_progress shows up in two places:

  1. Polling the run endpoint (/threads/{thread_id}/runs/{run_id}) repeatedly returns "status": "in_progress".
  2. The Playground displays a spinning indicator and never yields the assistant’s reply.

Even if you see a single message appear, subsequent messages stay stuck. The underlying HTTP request may still be open, or the server may be silently retrying internal steps without advancing the run’s status.

Common Root Causes

While OpenAI has not published an exhaustive error catalogue, community reports and the API’s behavior point to a few recurring patterns:

1. Tool‑call loops or nonsensical function emissions

The assistant may decide to invoke a tool that either:

  • Does not exist in your tool set,
  • Requires parameters that cannot be satisfied, or
  • Triggers another tool call immediately, creating an endless chain.

When the model keeps emitting tool calls that the execution environment cannot resolve, the run never actually finish, the status remains in_progress while the server retries internally.

2. Model‑specific degradation

Certain preview models (e.g., gpt-4-turbo-preview, gpt-4-0125-preview) have shown intermittent regressions where tool usage becomes unreliable. Switching to a stable, older model such as gpt-4 or gpt-3.5-turbo-0125 often resolves the hang, suggesting the problem lies in the model’s reasoning or tool‑selection logic rather than the Assistants infrastructure itself.

3. Missing or malformed tool definitions

If you pass a tool schema that the model cannot parse (e.g., missing type, incorrect properties format, or unsupported data types), the model may still attempt to call it, fail silently, and keep retrying.

4. Lack of client‑side timeout or retry logic

The Assistants API does not automatically abort a run that is taking too long. If your polling loop waits indefinitely for a status change that never arrives, you experience the same symptom as a true server‑side stall. Implementing a watchdog that cancels the run after a reasonable interval prevents resource exhaustion and lets you surface a clear error to users.

5. Run expiration without clear feedback

Runs can transition to the expired state after a period of inactivity (typically several minutes). If you are not monitoring for expired, you may mistakenly interpret the lack of progress as a permanent hang.

Diagnosing a Stuck Run

Before applying fixes, gather as much information as possible about what the assistant is actually doing.

Retrieve Run Steps

curl -X GET "https://api.openai.com/v1/threads/{thread_id}/runs/{run_id}/steps" \
  -H "Authorization: Bearer $OPENAI_API_KEY"

Each step contains:

  • step_type (e.g., tool_calls, message_creation),
  • tool_calls array (if any),
  • status (in_progress, completed, failed).

If you see a repeating pattern of the same tool call IDs or a step that never advances to completed, you have identified the looping behavior.

Inspect the Latest Message

Check the thread’s messages for any partial output:

curl -X GET "https://api.openai.com/v1/threads/{thread_id}/messages" \
  -H "Authorization: Bearer $OPENAI_API_KEY"

A missing assistant message or a message with role: "assistant" but empty content often accompanies a tool‑call stall.

Monitor Usage Metrics

In the OpenAI dashboard, view the usage tab for your organization. A sudden spike in token consumption without corresponding output can indicate the model is repeatedly invoking tools or generating internal reasoning that never surfaces.

Check Status.OpenAI

Before diving too deep, verify that the platform reports no ongoing incidents at <https://status.openai.com>. A broad outage can manifest as runs stuck in in_progress.

Practical Mitigation Strategies

Once you confirm the run is not progressing, apply one or more of the following techniques. Choose the approach that best fits your application’s latency and reliability requirements.

Implement a Watchdog with Automatic Cancellation

Set a maximum allowable elapsed time for a run (e.g., 30 seconds). If the run hasn’t moved to a terminal state, cancel it and either retry with a fresh run or fall back to a simpler flow.


def run_with_timeout(assistant_id, thread_id, max_wait=30):
    run = openai.beta.threads.runs.create(
        thread_id=thread_id,
        assistant_id=assistant_id
    )
    start = time.time()
    while True:
        run = openai.beta.threads.runs.retrieve(
            thread_id=thread_id,
            run_id=run.id
        )
        if run.status in ("completed", "failed", "cancelled", "expired"):
            return run
        if time.time() - start > max_wait:
            # Cancel the run to free server‑side resources
            openai.beta.threads.runs.cancel(
                thread_id=thread_id,
                run_id=run.id
            )
            raise TimeoutError(f"Run {run.id} exceeded {max_wait}s")
        time.sleep(1)  # poll interval

Add Exponential Backoff to Polling

Rather than polling every second blindly, increase the delay after each unsuccessful check. This reduces load on the API and gives the server more time to recover from transient glitches.

def poll_run(thread_id, run_id, base_delay=1, factor=2, max_delay=16):
    delay = base_delay
    while True:
        run = openai.beta.threads.runs.retrieve(
            thread_id=thread_id,
            run_id=run_id
        )
        if run.status in ("completed", "failed", "cancelled", "expired"):
            return run
        time.sleep(delay)
        delay = min(delay * factor, max_delay)

Validate and Sanitize Tool Definitions

Before creating an assistant, run a quick JSON‑schema validation on each tool. Ensure:

  • Every tool has a "type": "function" field,
  • The "function" object contains a valid "name" and "parameters" schema,
  • No unsupported keywords (e.g., "strict": true) are present.

If you generate tools dynamically, wrap the creation in a try/except block and log any schema errors.

Fallback to a More Stable Model

If you observe the hang only with a specific preview model, switch the assistant’s model field to a known‑stable version. For many users, gpt-4 or gpt-3.5-turbo-0125 eliminates the looping behavior while still offering strong reasoning.

Limit Tool Chains in Your Instructions

Explicitly instruct the assistant to avoid unnecessary tool usage. For example:

“Only call the get_weather tool if the user asks for a forecast. Do not invoke any tools for greeting or small talk.”

Clear instructions reduce the chance the model hallucinates a tool call.

Handle Expired Runs Gracefully

When a run reaches expired, treat it as a failed attempt and either:

  • Inform the user that the request timed out,
  • Retry with a new thread (sometimes a fresh context helps), or
  • Log the incident for later analysis.

When to Escalate to OpenAI Support

If you have:

  • Verified that your tool schemas are correct,
  • Confirmed the model is not the source of the regression,
  • Implemented a watchdog and still see >80% of runs stall,
  • Seen no platform‑wide incident on status.openai.com,

then it is reasonable to open a support ticket. Include:

  • The assistant ID, thread ID, and a sample run ID,
  • Approximate timestamps (UTC),
  • The exact polling code you are using,
  • Any relevant run‑step snippets showing repeated tool calls,
  • Information about the model and tool set you employed.

OpenAI’s support team can investigate backend logs for internal retries or error states that are not exposed via the public API.

Cost Considerations

A run that remains in in_progress continues to consume compute resources on OpenAI’s side, which you are billed for (tokens used by the model during its internal reasoning). To avoid runaway costs:

  • Always enforce a client‑side timeout,
  • Cancel stale runs promptly,
  • Monitor your daily usage and set alerts for abnormal token spikes.

While OpenAI does not currently offer automatic refunds for stalled runs, demonstrating a pattern of excessive usage due to a known bug can strengthen a case for goodwill gestures when you contact support.

Preventive Checklist for Production Deployments

✅ ItemWhy it Matters
Validate tool schemas before assistant creationPrevents nonsensical tool emissions
Pin to a stable model version (avoid preview unless required)Reduces risk of regressions
Set a max run duration (e.g., 20‑30 s) with automatic cancelGuards against infinite loops
Use exponential backoff when polling statusLowers API load and smooths transient glitches
Log run steps for every failed or stalled runGives you data to diagnose repeats
Monitor usage metrics and set anomaly alertsDetects silent token‑burn early
Document a fallback path (e.g., direct completions API)Ensures service continuity if Assistants falters
Review assistant instructions regularlyKeeps the model focused on needed actions

Conclusion

The “in_progress” hang in the OpenAI Assistants API is usually a symptom of the assistant getting trapped in a tool‑call loop, a model‑specific hiccup, or missing client‑side safeguards. By inspecting run steps, validating your tool definitions, enforcing timeouts, and employing retry‑with‑backoff patterns, you can turn an unreliable experience into a robust one. Keep an eye on platform status, maintain clear usage alerts, and don’t hesitate to reach out to OpenAI with detailed diagnostics when the problem persists beyond your controls. With these practices in place, you’ll reap the benefits of the Assistants API’s powerful reasoning while minimizing downtime and unexpected costs.

Share this post:
OpenAI Assistants API Run Stuck in \"in_progress\": Causes, Diagnosis, and Fixes