openclaw - 💡(How to fix) Fix [Bug]: image-understanding deadline budget collapses to 1ms via Math.max(1, …), causing tight retry loop

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

The image-understanding tool has a "deadline-budget" timeout bug that causes it to enter a tight retry loop returning "image description timed out after 1ms" whenever the per-call timeoutMs deadline is exhausted across retries.

When resolveImageDescriptionTimeoutMs(timeoutMs, startedAtMs) is called after the original deadline has elapsed, it computes a negative remaining budget and then forces it to 1 via Math.max(1, ...). The next call then sees timeoutMs=1ms, the setTimeout fires almost immediately, the controller aborts, and the call rejects with "image description timed out after 1ms". This repeats indefinitely.

Error Message

In a UberPC v2026.5.7 install with default tools.media (no explicit config), send a slow vision call that hits or exceeds 60s, then watch subsequent retries (within the same outer agent run / shared startedAtMs) all fail with the 1ms error string. reject(new Error(image description timed out after ${params.timeoutMs}ms)); The issue: Math.max(1, ...) forces a stuck-at-1ms behavior once the deadline budget is exhausted, rather than returning a clear error like "deadline exceeded" or letting retries get a fresh budget. #17 toolResult: {"status":"error","error":"image description timed out after 1ms"} #19 toolResult: {"status":"error","error":"image description timed out after 1ms"} #21 toolResult: {"status":"error","error":"image description timed out after 1ms"}

  1. Return a distinct error like "image description deadline exceeded" so the agent loop can break out of retries, OR
  2. Surface the original timeout value (e.g. 60000ms) in the error string when the resolved budget collapsed to 1ms, so logs make the root cause obvious. Option 1 with an unrecoverable error class is the cleanest fix; combined with refusal-to-retry on the agent side, it prevents the tight retry loop entirely.
  • #78717 (CLOSED): "media-understanding report image description timed out after upgrade from v4.23 to v5.4" — same error string, but root cause there was missing timeout config. Different from this deadline-budget mutation.

Root Cause

  1. Return a distinct error like "image description deadline exceeded" so the agent loop can break out of retries, OR
  2. Treat each retry as a fresh timeout window (preferred for usability, since retries are typically intentional), OR
  3. Surface the original timeout value (e.g. 60000ms) in the error string when the resolved budget collapsed to 1ms, so logs make the root cause obvious.

Fix Action

Workaround

Setting tools.media.image.timeoutSeconds to a high value (e.g. 300) makes the initial budget large enough that single-shot failures don't exhaust it. But the underlying bug remains for any genuinely slow vision call that hits the configured deadline.

Code Example

function resolveImageDescriptionTimeoutMs(timeoutMs, startedAtMs) {
    if (typeof timeoutMs !== "number" || !Number.isFinite(timeoutMs) || timeoutMs <= 0) return;
    return Math.max(1, Math.floor(timeoutMs - (Date.now() - startedAtMs)));
}

async function withImageDescriptionTimeout(params) {
    if (params.timeoutMs === void 0) return await params.task;
    let timeout;
    try {
        return await Promise.race([params.task, new Promise((_, reject) => {
            timeout = setTimeout(() => {
                params.controller.abort();
                reject(new Error(`image description timed out after ${params.timeoutMs}ms`));
            }, params.timeoutMs);
        })]);
    } finally {
        if (timeout) clearTimeout(timeout);
    }
}

---

#16 assistant TOOL_CALL [image]: {"image": "...png", "prompt": "Read all visible text..."}
#17 toolResult: {"status":"error","error":"image description timed out after 1ms"}
#18 assistant TOOL_CALL [image]: {"image": "...png", "prompt": "..."}
#19 toolResult: {"status":"error","error":"image description timed out after 1ms"}
#20 assistant TOOL_CALL [image]: ...
#21 toolResult: {"status":"error","error":"image description timed out after 1ms"}
#24 assistant TOOL_CALL [image]: ...
#26 toolResult: image description timed out after 1ms
RAW_BUFFERClick to expand / collapse

Bug type

Bug (correctness)

Beta release blocker

No

Summary

The image-understanding tool has a "deadline-budget" timeout bug that causes it to enter a tight retry loop returning "image description timed out after 1ms" whenever the per-call timeoutMs deadline is exhausted across retries.

When resolveImageDescriptionTimeoutMs(timeoutMs, startedAtMs) is called after the original deadline has elapsed, it computes a negative remaining budget and then forces it to 1 via Math.max(1, ...). The next call then sees timeoutMs=1ms, the setTimeout fires almost immediately, the controller aborts, and the call rejects with "image description timed out after 1ms". This repeats indefinitely.

Reproduction

In a UberPC v2026.5.7 install with default tools.media (no explicit config), send a slow vision call that hits or exceeds 60s, then watch subsequent retries (within the same outer agent run / shared startedAtMs) all fail with the 1ms error string.

Evidence

From dist/image-DgSZlFfp.js (v2026.5.7):

function resolveImageDescriptionTimeoutMs(timeoutMs, startedAtMs) {
    if (typeof timeoutMs !== "number" || !Number.isFinite(timeoutMs) || timeoutMs <= 0) return;
    return Math.max(1, Math.floor(timeoutMs - (Date.now() - startedAtMs)));
}

async function withImageDescriptionTimeout(params) {
    if (params.timeoutMs === void 0) return await params.task;
    let timeout;
    try {
        return await Promise.race([params.task, new Promise((_, reject) => {
            timeout = setTimeout(() => {
                params.controller.abort();
                reject(new Error(`image description timed out after ${params.timeoutMs}ms`));
            }, params.timeoutMs);
        })]);
    } finally {
        if (timeout) clearTimeout(timeout);
    }
}

The issue: Math.max(1, ...) forces a stuck-at-1ms behavior once the deadline budget is exhausted, rather than returning a clear error like "deadline exceeded" or letting retries get a fresh budget.

Observed in production

On UberPC (Windows 10 Pro v1909, OpenClaw v2026.5.7) the bot received 5 image attachments in a Slack channel. The first image-tool call hit the default 60s timeout. Every subsequent retry then returned image description timed out after 1ms within milliseconds. Agent looped on retries for ~6 hours, accumulating ~25 minutes of CPU and triggering gateway event-loop blocks observable via http://localhost:18789/health timing out on the 5-minute health probe.

Session transcript fragment (from agents/main/sessions/68c6bbef-*.jsonl):

#16 assistant TOOL_CALL [image]: {"image": "...png", "prompt": "Read all visible text..."}
#17 toolResult: {"status":"error","error":"image description timed out after 1ms"}
#18 assistant TOOL_CALL [image]: {"image": "...png", "prompt": "..."}
#19 toolResult: {"status":"error","error":"image description timed out after 1ms"}
#20 assistant TOOL_CALL [image]: ...
#21 toolResult: {"status":"error","error":"image description timed out after 1ms"}
#24 assistant TOOL_CALL [image]: ...
#26 toolResult: image description timed out after 1ms

Expected behavior

When the deadline budget is exhausted, either:

  1. Return a distinct error like "image description deadline exceeded" so the agent loop can break out of retries, OR
  2. Treat each retry as a fresh timeout window (preferred for usability, since retries are typically intentional), OR
  3. Surface the original timeout value (e.g. 60000ms) in the error string when the resolved budget collapsed to 1ms, so logs make the root cause obvious.

Option 1 with an unrecoverable error class is the cleanest fix; combined with refusal-to-retry on the agent side, it prevents the tight retry loop entirely.

Workaround

Setting tools.media.image.timeoutSeconds to a high value (e.g. 300) makes the initial budget large enough that single-shot failures don't exhaust it. But the underlying bug remains for any genuinely slow vision call that hits the configured deadline.

Environment

  • OpenClaw: v2026.5.7
  • Node: 22.x
  • OS: Windows 10 Pro v1909
  • Image provider: Anthropic (claude-opus-4-7 native vision via active reply model auto-detect)
  • Default tools.media (no override)

Related issues

  • #78717 (CLOSED): "media-understanding report image description timed out after upgrade from v4.23 to v5.4" — same error string, but root cause there was missing timeout config. Different from this deadline-budget mutation.
  • #67889 (CLOSED): hardcoded 60s. Fixed in current main.
  • #62944 (CLOSED): hardcoded 30s. Fixed.

This issue is distinct: it concerns the post-fix behavior where tools.media.models.timeoutSeconds IS respected, but the deadline budget across retries collapses to 1ms.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

When the deadline budget is exhausted, either:

  1. Return a distinct error like "image description deadline exceeded" so the agent loop can break out of retries, OR
  2. Treat each retry as a fresh timeout window (preferred for usability, since retries are typically intentional), OR
  3. Surface the original timeout value (e.g. 60000ms) in the error string when the resolved budget collapsed to 1ms, so logs make the root cause obvious.

Option 1 with an unrecoverable error class is the cleanest fix; combined with refusal-to-retry on the agent side, it prevents the tight retry loop entirely.

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - 💡(How to fix) Fix [Bug]: image-understanding deadline budget collapses to 1ms via Math.max(1, …), causing tight retry loop