NousResearch/hermes-agent · warning

clipboard image is empty

Error message

clipboard image is empty

What it means

uploadChatImage rejects with this when the pasted clipboard Blob has size 0. Because the dashboard Chat tab is an xterm mirror of a TUI inside the gateway, images must be uploaded from the browser's own clipboard bytes; an empty blob means the paste event carried no actual image data.

Source

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

    reader.readAsDataURL(file);
  });
}

/**
 * Upload a browser clipboard/drop image to ``HERMES_HOME/images`` via the
 * dedicated chat upload endpoint and return the absolute gateway path.
 *
 * The dashboard Chat tab is an xterm mirror of a TUI running INSIDE the
 * gateway. The container has no access to the browser's clipboard, so the
 * server-side ``clipboard.paste`` path can never see a pasted image.
 * Upload the bytes the browser already holds, then hand the path to the
 * TUI's ``/image`` command.
 */
export async function uploadChatImage(
  blob: Blob,
  profile = "",
): Promise<ChatImageUploadResult> {
  if (blob.size === 0) throw new Error("clipboard image is empty");
  if (blob.size > MAX_IMAGE_BYTES) {
    const mb = Math.round(MAX_IMAGE_BYTES / (1024 * 1024));
    throw new Error(`image too large (max ${mb} MB)`);
  }

  const mime = blob.type || "image/png";
  const ext = IMAGE_MIME_EXT[mime] || "png";
  const filename =
    blob instanceof File && blob.name
      ? blob.name
      : `clipboard.${ext}`;
  const file =
    blob instanceof File
      ? blob
      : new File([blob], filename, { type: mime });

  const dataUrl = await fileToDataUrl(file);
  const qs = profile ? `?profile=${encodeURIComponent(profile)}` : "";

View on GitHub (pinned to c896c09c42)

Solutions

  1. Re-copy the image (retake the screenshot) and paste again — confirm the source app actually placed image bytes on the clipboard.
  2. If this recurs in RDP/VM environments, verify clipboard sharing is enabled; or save the image to a file and attach it instead of pasting.
  3. In code, skip the upload call when event.clipboardData contains no non-empty image item.

Example fix

// before
const blob = new Blob([], { type: 'image/png' })
await uploadChatImage(blob)

// after
if (blob.size === 0) return  // nothing to upload
await uploadChatImage(blob)
Defensive patterns

Strategy: validation

Validate before calling

function extractPasteImage(items: DataTransferItemList): Blob | null {
  for (const item of items) {
    if (item.kind === 'file' && item.type.startsWith('image/')) {
      const blob = item.getAsFile()
      if (blob && blob.size > 0) return blob
    }
  }
  return null // nothing usable — skip upload entirely
}

Type guard

const isNonEmptyImage = (b: Blob | null): b is Blob =>
  !!b && b.size > 0 && b.type.startsWith('image/')

Try / catch

try {
  await uploadChatImage(blob)
} catch (err) {
  if (String(err).includes('empty')) { toast('Nothing on the clipboard — re-copy the image'); return }
  throw err
}

Prevention

When it happens

Trigger: A paste handler constructs a Blob from an empty clipboard item, or the OS clipboard contains an image entry with zero bytes (e.g. a screenshot tool that failed mid-capture, or a virtualized environment with a broken clipboard channel).

Common situations: Pasting from remote-desktop/RDP sessions with clipboard redirection issues, pasting immediately after a failed screenshot, or programmatic paste dispatch in tests with no real clipboard payload.

Related errors


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