NousResearch/hermes-agent · error

text || HTTP

Error message

text || HTTP ${res.status}

What it means

The image upload POST to /api/chat/image-upload returned a non-OK HTTP status. The error prefers the server's response body text (which usually carries the backend's own error message) and falls back to `HTTP <status>` only when the body is empty. This is the same pattern as the dashboard's generic authedFetch error, applied to the chat image endpoint.

Solutions

  1. Read the server text in the error message — it usually names the exact backend cause (invalid data URL, payload too large, auth required).
  2. For 401: reload the dashboard to refresh auth, then paste again.
  3. For 413: raise the proxy's request body limit or send a smaller image (see the max-MB error).
  4. For 500: check gateway logs for the write failure (permissions/disk) in the upload target directory.
Defensive patterns

Strategy: try-catch

Try / catch

try {
  const { path } = await uploadChatImage(blob, profile)
} catch (err) {
  const msg = String(err)
  if (msg.startsWith('401') || msg.startsWith('403')) { location.reload(); return }
  if (msg.startsWith('413')) { toast('Image too large for the server'); return }
  toast(`Upload failed: ${msg}`)
}

Prevention

When it happens

Trigger: Uploading a data_url whose base64 is corrupt or whose mime is disallowed (400), uploading when the session expired (401), hitting a server-side body-size limit (413), or the gateway erroring while writing the upload to disk (500).

Common situations: Session cookie expired between page load and paste; reverse proxy (nginx/caddy) with a smaller client_max_body_size than the dashboard's limit; disk-full or permission errors in the gateway's upload directory.

Related errors


AI-assisted analysis of NousResearch/hermes-agent@c896c09c42 (2026-08-14). Data as JSON: /api/errors/187bd343c81a2378. Report an issue: GitHub.

Appendix: source

Thrown at web/src/lib/chatImagePaste.ts:156

  const file =
    blob instanceof File
      ? blob
      : new File([blob], filename, { type: mime });

  const dataUrl = await fileToDataUrl(file);
  const qs = profile ? `?profile=${encodeURIComponent(profile)}` : "";
  const res = await authedFetch(`/api/chat/image-upload${qs}`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      data_url: dataUrl,
      filename,
    }),
  });

  if (!res.ok) {
    const text = await res.text().catch(() => res.statusText);
    throw new Error(text || `HTTP ${res.status}`);
  }

  const uploaded = (await res.json()) as ChatImageUploadResult;
  if (!uploaded?.path) {
    throw new Error("image upload did not return a path");
  }
  return uploaded;
}

View on GitHub (pinned to c896c09c42)