openclaw - 💡(How to fix) Fix Inline image attachment validator ignores per-agent model and uses system default

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 chat-attachment validator in agent.run resolves the model via resolveSessionModelRef(cfg, entry, undefined) — passing undefined as the third argument. When the request is for the first message in a fresh session, the session entry has no persisted model, so resolveSessionModelRef falls back to the system default model (agents.defaults.model.primary) instead of the per-agent model configured under agents.list[].model.

If the system default is text-only (e.g. ollama-cloud/deepseek-v4-flash) but the agent uses a vision-capable model (e.g. ollama-cloud/gemma4:31b), supportsInlineImages resolves to false and the request is rejected with:

UnsupportedAttachmentError: attachment attachment-1: active model does not accept image inputs

After the agent successfully processes a non-attachment message (text-only), the session entry persists model and modelProvider, and subsequent attachment requests work correctly. So the bug only affects the first message of a fresh session.

Error Message

UnsupportedAttachmentError: attachment attachment-1: active model does not accept image inputs

Root Cause

Root cause (verified by reading source)

Fix Action

Fix / Workaround

Workaround: send any text-only message first; the session is then persisted with the correct model, and subsequent images work.

Code Example

UnsupportedAttachmentError: attachment attachment-1: active model does not accept image inputs

---

let baseProvider: string | undefined;
let baseModel: string | undefined;
if (requestedSessionKeyRaw) {
  const { cfg: sessCfg, entry: sessEntry } = loadSessionEntry(requestedSessionKeyRaw);
  const modelRef = resolveSessionModelRef(sessCfg, sessEntry, undefined);  // ← agentId not passed
  baseProvider = modelRef.provider;
  baseModel = modelRef.model;
}

---

// session-reset path (already correct):
const resetSessionAgentId = resolveAgentIdFromSessionKey(requestedSessionKey);
const resetBaseModelRef = resolveSessionModelRef(resetCfg, resetSessionEntry, resetSessionAgentId);

---

if (requestedSessionKeyRaw) {
  const { cfg: sessCfg, entry: sessEntry } = loadSessionEntry(requestedSessionKeyRaw);
  const sessionAgentId = resolveAgentIdFromSessionKey(requestedSessionKeyRaw);
  const modelRef = resolveSessionModelRef(sessCfg, sessEntry, sessionAgentId);
  baseProvider = modelRef.provider;
  baseModel = modelRef.model;
}
RAW_BUFFERClick to expand / collapse

Bug type

Behavior bug — inline image attachments rejected for the first message in a fresh session, even when the agent's configured model supports image input.

Summary

The chat-attachment validator in agent.run resolves the model via resolveSessionModelRef(cfg, entry, undefined) — passing undefined as the third argument. When the request is for the first message in a fresh session, the session entry has no persisted model, so resolveSessionModelRef falls back to the system default model (agents.defaults.model.primary) instead of the per-agent model configured under agents.list[].model.

If the system default is text-only (e.g. ollama-cloud/deepseek-v4-flash) but the agent uses a vision-capable model (e.g. ollama-cloud/gemma4:31b), supportsInlineImages resolves to false and the request is rejected with:

UnsupportedAttachmentError: attachment attachment-1: active model does not accept image inputs

After the agent successfully processes a non-attachment message (text-only), the session entry persists model and modelProvider, and subsequent attachment requests work correctly. So the bug only affects the first message of a fresh session.

Reproduction

Tested deterministically on 2026.4.27 and verified the bug is still present on v2026.5.7 and main.

  1. Configure two providers/models such that:
    • agents.defaults.model.primary is a text-only model (e.g. ollama-cloud/deepseek-v4-flash, input: ["text"])
    • One agent in agents.list overrides model to a vision-capable one (e.g. ollama-cloud/gemma4:31b, input: ["text", "image"])
  2. Open a fresh chat with the per-agent-overridden agent (no prior session — agents/<id>/sessions/sessions.json does not exist)
  3. Send a message with an image attachment as the first message

Actual: request rejected in ~35 ms with UnsupportedAttachmentError: ... active model does not accept image inputs.

Expected: image accepted, model resolution uses the per-agent override, request proceeds.

Workaround: send any text-only message first; the session is then persisted with the correct model, and subsequent images work.

Root cause (verified by reading source)

src/gateway/server-methods/agent.ts:633 (current main, identical in v2026.5.7):

let baseProvider: string | undefined;
let baseModel: string | undefined;
if (requestedSessionKeyRaw) {
  const { cfg: sessCfg, entry: sessEntry } = loadSessionEntry(requestedSessionKeyRaw);
  const modelRef = resolveSessionModelRef(sessCfg, sessEntry, undefined);  // ← agentId not passed
  baseProvider = modelRef.provider;
  baseModel = modelRef.model;
}

resolveSessionModelRef(cfg, entry, agentId) returns the agent-specific model only when agentId is provided. Without it, it falls through to resolveConfiguredModelRef with DEFAULT_PROVIDER/DEFAULT_MODEL (the system default).

The same file already imports resolveAgentIdFromSessionKey and uses it elsewhere in this handler — for example for the session reset branch a few lines below, and at multiple other call sites in the same file (lines 208, 227, 741, 761, 801, 860, 869, …):

// session-reset path (already correct):
const resetSessionAgentId = resolveAgentIdFromSessionKey(requestedSessionKey);
const resetBaseModelRef = resolveSessionModelRef(resetCfg, resetSessionEntry, resetSessionAgentId);

The image-validation path is the only one that drops the agentId.

Suggested fix

Replace undefined with resolveAgentIdFromSessionKey(requestedSessionKeyRaw):

if (requestedSessionKeyRaw) {
  const { cfg: sessCfg, entry: sessEntry } = loadSessionEntry(requestedSessionKeyRaw);
  const sessionAgentId = resolveAgentIdFromSessionKey(requestedSessionKeyRaw);
  const modelRef = resolveSessionModelRef(sessCfg, sessEntry, sessionAgentId);
  baseProvider = modelRef.provider;
  baseModel = modelRef.model;
}

This matches the pattern used by every other resolveSessionModelRef call site in the same handler.

OpenClaw version

2026.4.27 (verified) — also reproducible on v2026.5.7 and main by source inspection.

Operating system

Docker (linux/amd64), ghcr.io/heypinchy/pinchy-openclaw:dev (based on upstream OpenClaw image).

Install method

Docker image

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…

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 Inline image attachment validator ignores per-agent model and uses system default